题目建议: 大家能把 704 掌握就可以,35.搜索插入位置 和 34. 在排序数组中查找元素的第一个和最后一个位置 ,如果有时间就去看一下,没时间可以先不看,二刷的时候在看。
先把 704写熟练,要熟悉 根据 左闭右开,左闭右闭 两种区间规则 写出来的二分法。
题目链接:https://leetcode.cn/problems/binary-search/
文章讲解:https://programmercarl.com/0704.%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.html
视频讲解:https://www.bilibili.com/video/BV1fA4y1o715
这道题没有思路,直接看的视频。我觉得关键在于想到,首先这是个有序数组。要找到目标值,那么这会是个循环,循环有哪些?用哪个?效率高的话显然每一次循环,循环区间都应该有所缩减,意味着这个区间两头位置的值都有可能变,不知道哪头会变(其实这里和27也有相似,那就是这里其实也是拿一个变量去记录位置,考虑位置应该发生什么变化才能完成循环),for循环显然不够灵活,那么用 while 循环,那么下一个问题就是这个循环区间怎么定义怎么取?ok,区间都有开闭,我们先假设左闭右开,然后while的话就要考虑如何跳出循环,也就是是否有等于号,那么针对左闭右开的区间,左显然不能等于右,那么while这里就不应该有等号,这样的话思路就顺下来了。
下次拿到题记得先看:数组是否有序?
看视频后个人解法:
注意:
mid写法与溢出:
mid = left + (right - left) / 2 等同于 mid = (left + right) / 2;但是前一种写法可以避免 left+right 过大溢出,因为如果是(left+right)/2,会先计算括号内加法,可能会导致超界即溢出。而 right-left 是待查数组的大小,取一半加上left偏移量。
两个是数学上的恒等式,在计算机里两个 int 相加可能会溢出,先减后加确实可以用于更大的数组,即当数组长度过大时就有可能溢出。比如java的int最大值是2^31-1,如果left和right都超过最大值的一半,在进行相加的那边就溢出了,就变成负数了。
还有不管区间是左闭右闭还是左闭右开,为什么左边一般是闭,而不是开?
知名开源项目,基本大家默认都是用 左闭右开。左闭右开和左闭左开是因为防止左边界超过原有的边界,防止出现出现非法访问地址导致程序出错。那右边为啥不担心非法访问?因为右边可以控制,左边 下标 0,就不能再往左取数,右边 你可以再往右取数。
题目建议: 暴力的解法,可以锻炼一下我们的代码实现能力,建议先把暴力写法写一遍。 双指针法 是本题的精髓,今日需要掌握,至于拓展题目可以先不看。
题目链接:https://leetcode.cn/problems/remove-element/
文章讲解:https://programmercarl.com/0027.%E7%A7%BB%E9%99%A4%E5%85%83%E7%B4%A0.html
视频讲解:https://www.bilibili.com/video/BV12A4y1Z7LP
个人解法(暴力解法)
写成暴力解法的原因:
1. 错误理解题意。“不要使用额外的数组空间” → 理解为:“不要使用额外的空间” → 理解为:“不能创建新变量”,但实际上在循环的时候也创建变量了,so。。对自己很无语;
2. 那么假如我可以创建变量,我也没想到双指针,原因在于,数组注意考虑内容和位置两个方面!暴力双层循环就是我即使创建了变量,我也只想到用这个变量记录数组的内容,也就是值,但如果这个变量记录数组的位置呢?那如果记的是位置,这个变量要怎么变才能完成循环呢?这样就能想到了(而且,就算是暴力循环,你在循环什么啊,不就是位置(索引)么,我循环了一次位置,再循环一次位置以实现覆盖,那这个第二次位置循环除了循环来实现还有什么其他办法吗)
3. 而且第一遍时候“正确版”中13、14行也写错了,没有想到值覆盖的话整体前移,相对应的 i 得从新覆盖后的开始,也就是要 i--;result--同理。
今日时长:
19:00 - 22:00 3h
敲一行就很棒!!!