算法之路(一)

作者 : D. Star.
专栏 :算法小能手
今日分享 : 如何学习?
在学习的过程中,不仅要知道如何学习,还要知道避免学习的陷阱。1. 睡眠不足;2. 被动学习和重读;3. 强调标记或画线,仅仅是强调标记或画下大段课本内容并不会让你的头脑记住任何东西;4. 偷看问题的答案并且认为自己已经理解了;5. 填鸭式学习;6. 忽视书本,只做习题;7. 分心;8. 不去弄清楚你没理解的知识点;9. 惰性学习,只是学习简单的知识。避开这 9 个陷阱,同时破解掉陷阱,你就会找到学习的方法,提高你的成绩。在学习的过程中,不仅要知道如何学习,还要知道避免学习的陷阱。
算法之路(一)_第1张图片

文章目录

  • 1. 力扣的283题--移动零
    • ✔解题思路
    • ✔具体代码如下:
    • ✔总结
  • 2. 力扣的1089题--复写零
    • ✔解题思路:
    • ✔具体代码如下:
    • ✔总结:
  • 3. 力扣的11题--盛最多水的容器
    • ✔ 解题思路:
    • ✔具体代码如下:
    • ✔总结:
  • 4. 力扣611题-- 有效三角形的个数
    • ✔解题思路:
    • ✔具体代码如下:
    • ✔总结:
  • 5.力扣15题--三数之和
    • ✔解题思路:
    • ✔具体代码如下:
    • ✔总结:
  • 6. 力扣18题--四数之和
    • ✔解题思路:
    • ✔具体代码如下:
    • ✔总结:
    • 感谢家人的阅读,不准确的地方 欢迎在评论区指正!

1. 力扣的283题–移动零

做题链接:力扣的283题

✔解题思路

算法之路(一)_第2张图片

✔具体代码如下:

    public void moveZeroes(int[] nums) {
        int cur = 0;//指向当前遍历位置--”0“段的下一个
        int dest = 0;//指向非”0“段的末端
        while(cur<nums.length){
            if(nums[cur] == 0){
                cur++;
            }else{
                //交换dest+1和cur
                int tmp = nums[cur];
                nums[cur] = nums[dest];
                nums[dest] = tmp;
                dest++;cur++;
            }
        }
    }

✔总结

2. 力扣的1089题–复写零

做题链接:力扣的1089题

✔解题思路:

算法之路(一)_第3张图片
算法之路(一)_第4张图片

✔具体代码如下:

public static void duplicateZeros(int[] arr) {
        //首先找到最后一个需要复写的位置
        int cur = 0;//当前访问的位置
        int dest = -1;//复写后的长度
        int n = arr.length;
        while (cur < n) {
            if (arr[cur] == 0) dest += 2;
            else dest++;
            //先别急着移动cur,判断一下dest的位置关系
            if (dest >= n - 1) break;
            cur++;
        }
        //处理一下边界i情况
        if (dest == n) {
            arr[n - 1] = 0;
            cur--;
            dest -= 2;
        }
        //从后往前复写
        while (cur >= 0) {
            if (arr[cur] == 0) {
                arr[dest--] = 0;
                arr[dest--] = 0;
                cur--;
            } else {
                arr[dest--] = arr[cur--];
            }
        }
    }

✔总结:

这题自己写的时候有点复杂,但是当知道用快慢指针的时候,瞬间恍然大悟,感叹数学和代码结合的每秒!!!

3. 力扣的11题–盛最多水的容器

做题链接:力扣的11题

✔ 解题思路:

✔具体代码如下:

//解法一:暴力枚举--超时
//解法二:根据单调性,利用双指针--最优解
    public static  int maxArea1(int[] height) {
        //两个指针:左指针,右指针
        int left = 0;
        int right = height.length-1;
        int vMax = 0;//最大体积
        int lon = 0;//最短高度
        while (left < right) {
            //比较左右指针 指向的数组高度 哪一个最短,取最短的
            if(height[right] >= height[left]){
                lon = height[left];
            }else lon = height[right];
            //先计算一次体积,移动一个指针,比较最大体积
            int v = (right - left)*lon;
            //移动最短的指针
            if(height[right] >= height[left]){
                left++;
            }else right--;
            //比较最大体积
            if(v > vMax) vMax = v;
        }
        return vMax;
    }
    //代码优化
    public static  int maxArea(int[] height) {
        //两个指针:左指针,右指针
        int left = 0;
        int right = height.length-1;
        int vMax = 0;//最大体积
        while (left < right) {
            //比较左右指针指向的数组高度 哪一个最短,取最短的--用数学函数
            //先计算一次体积,比较最大体积
            int v = (right - left)*Math.min(height[right],height[left]);
            vMax = Math.max(v,vMax);
            //移动一个指针,移动最短的指针。
            if(height[right] >= height[left]){
                left++;
            }else right--;
        }
        return vMax;
    }

✔总结:

这中题型第一次见,刚做的时候被吓住了,想着该怎么解,感觉高度最大,宽度最大,肯定就是最大体积,但是宽度和高度是没有办法取最大值的,总会有一个是小一点的,那如何求最大的体积?可以说是毫无思路,看见解题思路,发现方法很巧妙!

4. 力扣611题-- 有效三角形的个数

做题链接:力扣611题

✔解题思路:

  1. 先排序,利用单调性,固定最大的数字
  2. 再从右边快速找出三元组
    算法之路(一)_第5张图片

✔具体代码如下:

    public int triangleNumber(int[] nums) {
                int len = nums.length;
        int left = 0;
        int c = len-1;
        int right = c-1;
        int count = 0;
        //先对nums进行排序
        Arrays.sort(nums);
        //当c<2时,停止循环判断
        while (c>=2){
            //当left>=right时,停止循环判断
            while (left < right) {
                int sum = nums[left]+nums[right];
                //当a+b>c时,说明a到b之间的数字和b相加都大于c
                //直接相减计算总数即可。
                //当a+b<=c时,就要移动left,判断有没有a+b>c的,但是left必须
                if(sum > nums[c]){
                    count += right-left;
                    right--;
                }else if(sum <= nums[c]){
                    left++;
                }
            }
            //当c的所有情况考虑完之后,就要向前移动c,继续判断。
            // 但是c不能<2,因为要保持包括c前面至少有三个数字。
            c--;
            right = c-1;
            left = 0;
        }
        return count;
    }

✔总结:

刚开始想到的就是暴力枚举,用三个for循环,但是工作量太大O(n3),时间太长。上述的解法很巧妙O(n2)!!!充分利用了单调性的特征。

5.力扣15题–三数之和

做题链接:力扣15题

✔解题思路:

算法之路(一)_第6张图片

✔具体代码如下:

    public static List<List<Integer>> threeSum(int[] nums) {
        //1. 排序
        Arrays.sort(nums);
        //创建一个二位数组
        List<List<Integer>> lists = new ArrayList<>();
        int n = nums.length;
        //2. 利用双指针算法
        for (int i = 0; i < n; ) {//相当于a
            if (nums[i] > 0) break;
            int left = i + 1, right = n - 1, tar = -nums[i];
            while (left < right) {
                int sum = nums[left] + nums[right];
                if (tar > sum) left++;
                else if (tar < sum) right--;
                else {
                    lists.add(new ArrayList<Integer>(Arrays.asList(nums[i], nums[left], nums[right])));
                    right--;
                    left++;
                    //3. 去重
                    // 将移动后数字与移动前数字进行比较
                    while (left < right && nums[left] == nums[left - 1]) left++;
                    while (right < n - 1 && left < right && nums[right] == nums[right + 1]) right--;
                }
            }
            i++;
            //4. 去重
            while (i < n && nums[i] == nums[i - 1]) i++;
        }
        return lists;
    }

✔总结:

这个题目很考验思维能力和代码能力。我们需要考虑到对数组去重+数组不漏+考虑越界问题。

6. 力扣18题–四数之和

做题链接:力扣18题

✔解题思路:

算法之路(一)_第7张图片

✔具体代码如下:

    public static List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> lists = new ArrayList<>();
        Arrays.sort(nums);
        if (nums[0] > 0 && target < 0 || nums[nums.length - 1] < 0 && target > 0) return lists;
        for (int i = 0; i < nums.length; ) {
            for (int j = i + 1; j < nums.length; ) {
                int c = j + 1, d = nums.length - 1;
                long  t = (long)target - nums[i] - nums[j];
                System.out.println(t);
                //对c,d区间进行查找,去重
                while (c < d) {
                    if (nums[c] + nums[d] < t) c++;
                    else if (nums[c] + nums[d] > t) d--;
                    else {
                        lists.add(Arrays.asList(nums[i], nums[j], nums[c], nums[d]));
                        c++;
                        d--;
                        while (c < d && nums[c] == nums[c - 1]) c++;
                        while (c < d && nums[d] == nums[d + 1]) d--;
                    }
                }
                //对[j]进行去重
                j++;
                while (j < nums.length && nums[j] == nums[j - 1]) j++;
            }
            //对[i]进行去重
            i++;
            while (i < nums.length && nums[i] == nums[i - 1]) i++;
        }
        return lists;
    }

✔总结:

long t = (long) target - nums[i] - nums[j];这里有个细节问题–我知道加减法的时候可能会越界,要用long型,但是我忘记后面也要强制转型了。我没有注意,导致我总是不知道我错哪里了,哭死我了!!!


感谢家人的阅读,不准确的地方 欢迎在评论区指正!

你可能感兴趣的:(算法小能手,算法)