刷的脑壳疼,在螺旋矩阵卡了很久,其他的 easy 题都也被卡,目前进度为 2-3 medium / day。

Monday (科普知识)

反码、补码

二进制的第一位是符号位,0是+,1是-,如果是1,怎么得到具体数字? 二进制数全都取反,再+1就是对应结果的的绝对值 。 例如-1的二进制数全为1,则将后31个1全取反并+1,得到 000…1 的十进制数就是1 。

如何把随机出现从 x 概率变为 x^3 概率?

Math.Max(Math.Random(),Math.Max(Math.Random(),Math.Random()));
注意:Random生成一个[0,1)

如何在 1-5(int)随机函数上生成1-7的随机函数?

直接把1-5改成随机生成0、1的函数,1、2返回0,3就return重来,4、5就返回1 。

再根据读书器返回0、1的函数处理:

1
return (f()<< 2)+ (f()<< 1)+(f()<< 0); //0或4 + 0或2 + 0或1

注意:

  • 如果直接 相乘 是不行的,因为只返回 0、1 乘了 7 就变成 0、7 。会缺失中间的数。
  • 0-7 有了,我们要 1-7 ,那只能 0-6 随机再+1 。1-7 只要遇 7 重来就行了。或者直接 0 重来。就不用再 +1。

为什么不能直接 (f() « 2) + (f() « 1) 呢?直接得到 0-6

  • 因为左移两位得到要么是0要么是4,左移一位是0或2,不移动0、1 。得到的具体数字不是范围,再将其相加,产生的和才是一个范围。

如何改变一个任一固定概率的随机0、1函数变为产生0、1都为50%的函数?

运行两次该函数,两次得到0的概率为 p^2 ,两次得到 1 的概率为 (1-p)^2 ;而一次 0 一次 1 的概率是 p*(1-p); 所以只要两次返回一次为 0 一次为 1 就行。不然就重新执行。

Tuesday

206. 反转链表

这题一定要按清楚头指针 pre、next 指针只是指针,不是一个结点指向另一个结点的指针。定义出这两个指针、画好图就很容易操作。这是单链表的反转,至于双链表就是多加了一个 last 指针指向上一个,只需要在存 next 时多存一个 last ,其他无需改动。

704. 二分查找

首先把 left 、mid 、 right 都定义出来。mid 的赋值,左右指针的跳转都在循环内完成,注意要 left=mid+1,right = mid-1,不然藏在边界的 target 就查不到了。

27. 移除元素

暴力解法:需要注意,i–;是因为既然当前值为 ?的点的右边所有点一切都左移了一位,所以现在的 i 指向的是已删除(被覆盖)的位置,该位置补了后面那位没被扫描的数字,而该次循环结束就要 i++了,所以会指向这个没扫描的下一个进行扫描,就漏掉一个了。再一个注意溢出边界问题,还有一个就是无限循环容易发生是因为 for 循环条件不能是 < length。而应该是 <size 这个自定义的,会随着更新而更新。

Wednesday

977. 有序数组的平方

这一题犯了一个总是犯的错误,总是忘记写返回值,以后第一步确定返回值,不明则??表示。
该题暴力解法就是平方再排序美滋滋~,但是时间复杂度为O(n^2),有O(n)的解法:双指针。
双指针解法一定要注意边界。

209. 长度最小的子数组

暴力解法要注意必须双层循环。为了避免要判断第一次 >target,把 len 初始值设为Interger.MAX_VALUE。滑动窗口:注意循环条件的边界。

Thursday

59. 螺旋矩阵 II

该题一定要注意别自己瞎套,while 的条件按照(循环次数)来。偏移量每次+2,从左到右,从上到下的循环条件要-offset。

203. 移除链表元素

先把头的 val 确定 ≠ val、≠null 再去定义 cur 等等其他结点,记得依次讨论头不为空(头的 val 为 val)、头为空(return head把整个链表有可能为空的情况删除整个链表了直接提前退出)。
不为空 && 头的 val == val 一定要把 ≠null 写在 && 前面,不然先判断 head.val 如果说 head == null ,那就直接报错了。
删除一定要 XXX.next = XXX.next 这样操作,自己定义的 cur 、 next 都只存一个地址,cur = nextNode 就是 cur 指针走到了 nextNode 这个位置。

Friday

707. 设计链表

只要把get、addIndex、delete写出来就行了,另外两个addHead、addTail直接调用这个addIndex就行了,至于get、delete都是用addIndex里面for查找的逻辑找到,主线就是写出addIndex,注意在addIndex里面 size++ 就够了,不要反复 ++ ;
另外自己定义一个 ListNode 的 class ,构造方法只要空参。成员变量 int val、 ListNode next;

24. 两两交换链表中的结点

非必要情况下,不要定义那么多 next、cur 结点,不然判空很头大,如果是在 while 内,cur、next、pre 都在变换,判空繁琐,在初始化时也要判空,还是尽量只定义一个 pre 结点,反正操作链表的元素有个 pre 就够了。

19.删除链表的倒数第N个节点

暴力解法:注意考虑传入的值的合法性。
进阶版本:首先一边扫描肯定无从下手,想想,倒数第 n 个结点,是正着数的第几个 ?

  • 显而易见:size-n 个,那如何拼凑出 size ?那是肯定要扫描一遍完整的链表结点的。

如果扫描 size++ 出长度那必然要再操作一遍,落入了扫描多次的圈套,so what?

  • 定义一个 fast 指针、一个 slow 指针,fast 扫描全文,而 slow 指向要被删除的结点的上一结点。如何凑出 size -n?先让 fast 走 n 次,再让 fast 和 slow 一起走剩下的 size-n次,此时fast 指向了最后一个元素,slow 指向了删除的结点的上一结点。

持续更新中…….. 敬请期待