嘿,各位技术潮人!好久不见甚是想念。生活就像一场奇妙冒险,而编程就是那把超酷的万能钥匙。此刻,阳光洒在键盘上,灵感在指尖跳跃,让我们抛开一切束缚,给平淡日子加点料,注入满满的passion。准备好和我一起冲进代码的奇幻宇宙了吗?Let's go!
我的博客:yuanManGan
本章采录我的四篇题山采玉专栏
目录
一.盛最多的水
题目来源 力扣11.盛最多水的容器
题目理解
题目给了关于线的长度的数组,任意选两个线,判断容器最大是多少,容积等于下标相减后乘以两条线最短的一条。
思路讲解
方法一暴力解法
我们一一枚举两条线,然后判断最大值。
这里等会就不编写代码了,判断一下时间复杂度很明显是O(n^2).
方法二双指针
假如我们枚举成这样以后,左边这条线比右边这条长,如果将左边这条线向右移动,不仅宽度会变小,长度再大也依据右边这条短的为主,而且宽度也变小了,我们就没有枚举下来的必要了,这时我们可以试试将右边这条线向左移动,继续进行上述判断,直到两条线重合。
方法:
1.定义两个指针left和right
2.先初始化容积为最初的
3.判断height[left] 与height[right]长度,短的--
4.更新容积
5.跳出循环
代码实现
方法二双指针
时间复杂度O(n).
二移动零
题目来源力扣283移动零
题目理解
题目要求将0元素移向右侧,左侧是非0元素,不能复制数组,只能在原地修改。
思路讲解
方法一
nums数组里面的元素从- 2^31到 2^31 -1,明显里面的数字是int类型就可以存储的。如果没有最后一句,我们第一想到的做法肯定也是,创建一个数组非0元素放在左,0放在右侧。然后再将原数组与新数组进行拷贝即可。这种方法的思想也是很重要的,我也会实现一下。
方法二
接下来就是重头戏了,双指针,这里的双指针并不是真正的指针,而是用变量来标记元素的下标,作用类似于指针,所以叫他指针。我们注意到数组被分为两部分,这也是很经典的板块问题。我们定了两个指针一个cur,一个i,我们用i来遍历数组。
可以将数组分为这三部分,我们可以将cur先定义为-1,当nums[ i ] == 0的时候,就可以直接i++跳过把这个元素给0部分就可以了,而当nums[ i ] ! = 0时,我们得将 nums[ i ]移动到cur的后面,而非0范围会变大,所以我们得将cur++,然后将nums[ cur ] 和nums[ i ]相交换就可以实现了。那么什么时候结束呢?当待遍历部分没有时,及i == n-1时。
希望同学们能自己画画图试一试,再来写个代码试试。
代码实现
方法一
分析代码时间复杂度,遍历nums n,拷贝数组 n 所以 O(n),空间复杂度,创建了新数组所以为O(n)。
方法二
分析代码时间复杂度,只遍历nums n 所以 O(n),空间复杂度,创建了cur和i指针所以为O(1)。
完结撒花!谢谢大家!
三复写零
题目来源力扣1089复写零
题目理解
有一个数组arr当出现0元素时复制一个0在后面并且将后面元素向后移动,但数组的长度不变。
题目还是要求就地移除。
思路讲解
方法一暴力求解
我们之前学习过的vector,可以使用里面的insert内置函数来解决,当元素为0时就在其后面插入一个零,但要求数组的元素个数不变,我们可以先记录没开始遍历时的元素个数,然后遍历数组之后进行尾删操作,即可。这个很好理解,但不是最优秀解。
方法二异地复写
如果没有要求就地移除,我们就可以采取异地复写操作,定义cur指针来遍历数组,dest指针来存储元素在新数组中当dest = n - 1时遍历结束。最后再拷贝回去就ok了。
最后结果
方法三双指针
如果我们定义的两个指针都指向前面的元素从前往后去遍历,遇到0就改两个,你就会发现我们会把还未遍历的元素修改了所以我们得从后往前遍历。
那问题来了cur和dest应该指向什么位置呢,dest不难像肯定是最后一个元素,curne?cur是不是改指向最后要修改的位置及看方法二中cur最后指向的位置。怎么找到这个位置我们先不管,我们先来实现一下找到了这个位置后的复写操作:
当cur指向的位置不是0时,直接把dest位置的值改成cur的值,然后统一移动一位。
而cur指向的位置是0时,将dest的值改成0,移动一位,再改成0 然后curdest移动一位。
接下来我们讲讲怎么找到cur指向的位置。
我们先让cur指向第一个元素,dest指向-1。
然后进行以下操作:
1.先判断cur是否为0。
2.根据cur的值判断dest移动一步还是两步。
3.判断dest有没有到达最后位置。
4.cur++;
但是还是存在特殊情况:当arr为[ 1, 0, 2, 3, 0, 4 ]时
dest就会发生越界,再力扣上会报错,那我们改怎么解决呢?当发生这种情况时一定是cur指向了0,我们只需要将n-1位置上的数修改成0再将dest移动两位,cur移动一位即可。
然后继续进行操作即可。
代码实现
方法一
分析复杂度 : 时间复杂度for循环 n 内层insert n while循环 忽略 所以 时间复杂度为O(n^2).
空间复杂度O(1)。
方法二
分析复杂度 : 时间复杂度for循环 n 内层可以忽略 所以 时间复杂度为O(n).
空间复杂度O(n), 因为创建了新数组。
方法三
分析复杂度 : 时间复杂度几个while循环都是n所以 时间复杂度为O(n).
空间复杂度O(1)。
四.快乐数
题目来源 力扣202快乐数
题目理解
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果这个过程 结果为 1,那么这个数就是快乐数。
结果要么是1要么无限循环。我们换个思路,最后结果是1那也算是无限循环1,
思路讲解
我们知道该过程始终会成环,有没有想起一道经典的题目 环形链表我们可以使用快慢指针来解决判断链表是否成环。这道题,我们可以使用同样的思路,只不过当fast等于slow时判断重复的数字是不是1即可。
解法:快慢双指针
1.定义快慢指针
2.慢指针向后移动一步,快指针向后移动两步
3判断相遇时的值是不是1
代码实现
数学扩展
怎么证明这个过程始终会成环?
鸽巢原理:也被称为抽屉原理,是组合数学中的一个重要概念。它的基本思想是:如果有n+1个或更多的物体要放入n个容器中,那么至少有一个容器里面包含两个或更多的物体。
假如这个数字最大值是int的最大值应该是10位数字我们假设是9999999999它进行一次操作后是
10*81 = 810,假设我们再次进行811次操作,一定会出现重复的数字,因为一次操作一定会产生一次结果,并且他们产生的结果一定小于等于810.
完结!over!