- leetcode11.https://leetcode-cn.com/problems/container-with-most-water/盛最多容器的水
- leetcode 283.https://leetcode-cn.com/problems/move-zeroes/移动零
- leetcode15.https://leetcode-cn.com/problems/3sum/三数之和
前两题用到双指针,双指针是一种技巧。双指针分为对撞指针和快慢指针,需要注意的是两种指针的区别,包括(1)双指针的初始位置;(2)双指针的移动方式(什么时候移动,移动方向,移动间隔,移动之前需要判断是否会越界);(3)遍历的结束条件。基本上解题套模板时也是这三点明确了就很好写。数组问题可以参考链接https://blog.csdn.net/justidle/article/details/106297779。
//对撞指针模板
function fn(int list[], int len) {
int left = 0;
int right = len - 1;
//遍历数组
while (left <= right) {
left++;
// 一些条件判断 和处理
... ...
right--;
}
}
/*1.盛最多水的容器。根据需要注意的三点,直接套模板就可以写出来。*/
/*2.需要注意的细节:用到了Math类的方法,一开始不知道用Math.min()和Math.max()函数,直接手动比较大小,代显得很冗余*/
class Solution {
public int maxArea(int[] height) {
//step1.初始值
int left = 0, right = height.length - 1, ans = 0, area = 0;
//step2.结束条件,遍历
while(left < right){
//step3.移动方式
area = Math.min(height[left], height[right]) * (right - left);
ans = Math.max(ans,area);
if(height[left] <= height[right]){
left ++;
}else right --;
}
return ans;
}
}
【移动零】这道题用到的是快慢指针,题本身不难,但是网上有两种高票解法很有意思,用到的思想,一个是慢指针标记不为0的元素相对位置,一个是用到快排思想,交换快慢指针的元素。【之前以为if、while等流程语句很简单,但做题的时候会常常出现这些地方得逻辑错误;另外一点,做完后发现对于题目给的参数没有判断,这也是常忽略的地方,需要对给的参数,如数组,要判断数组长度是否符合解题条件,数组是否为null...;还有就是注意题中要求,是不是要求空间复杂度,如不许额外开辟空间什么的...】
/*快慢指针模板*/
function fn(LinkList *list, int len) {
int slow = 0;
int fast = 1;
//遍历数组
while (slow != fast) {
slow++;
// 一些条件判断 和处理
... ...
fast+=2;
}
}
/*思路1:用j标记不为零的元素*/
class Solution{
public void moveZeroes(int[] nums) {
//1.初始位置
int i = 0;
int j = 0;
//2.结束条件
for(; i < nums.length; i ++){
int temp = 0;
if(nums[i] != 0)
//3.移动方式 (只要快指针对应的元素不为0,快指针对应的元素赋给慢指针,如果快慢指针不相等,则将快指针对应的元素置0,同时慢指针要向前移动)
temp = nums[i];
nums[j] = temp;
j ++;
if(i != j)
nums[i] = 0;
}
}
}
/*思路2:受快排启发,交换法*/
class Solution{
public void moveZeroes(int[] nums) {
//1.初始位置 2.结束条件
for(int i = 0, j = 0; i < nums.length; i ++){
int temp = 0;
//3.(慢指针)移动方式--只要快指针遍历到的元素不为0,就与慢指针对应的元素交换、同时慢指针向前移动。因为所有的0都是一个0
if(nums[i] != 0){
temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
j ++;
}
}
}
}
3.三数之和这个问题属于经典的老题,暴力解的时间复杂度为O(n^3),经典解法是可以将时间复杂度降到O(n^2)。算法真的等于数学,总能勾起做数学题时讨论边界条件的场景...
/*三数之和:摘抄国际站大佬的解法*/
/*这道题也用到碰撞指针,*/
1.public List<List<Integer>> threeSum(int[] num) {
2. Arrays.sort(num);
3. List<List<Integer>> res = new LinkedList<>(); //创建一个List,由于List是抽象接口,只能实现一个LinkedList或者ArrayList...
4. for (int i = 0; i < num.length-2; i++) { //三数问题转换成【1个数+两个数之和】问题...
5. if (i == 0 || (i > 0 && num[i] != num[i-1])) { //这里的&&之后是为了去重,如果num[i]元素与num[i - 1]相同,就没必要再求解了,符合题中要求:不重复
6. int lo = i+1, hi = num.length-1, sum = 0 - num[i];
7. while (lo < hi) {
8. if (num[lo] + num[hi] == sum) {
9. res.add(Arrays.asList(num[i], num[lo], num[hi])); //Arrays.asList()将数组转换成链表,这个函数是盲区....
10. while (lo < hi && num[lo] == num[lo+1]) lo++; //第10行和第11行,一开始没转明白为什么num[lo] == num[lo+1],lo还要++,把num[lo] == num[lo+1]理解成lo已经是移位了,其实while中只是判断...,然后如果lo和lo+1位置元素相同,那lo++就和lo相同,lo需要‘再’+1,与12行正好对应。 而且这里还要判断++后lo和hi的关系,是否符合循环条件了
11. while (lo < hi && num[hi] == num[hi-1]) hi--;
12. lo++; hi--;
13. } else if (num[lo] + num[hi] < sum) lo++;
14. else hi--;
15. }
16. }
17. }
18. return res;
19.}