算法之路(一)

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

1. 力扣的283题–移动零

做题链接:力扣的283题

✔解题思路

在这里插入图片描述

✔具体代码如下:

    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题

✔解题思路:

在这里插入图片描述
在这里插入图片描述

✔具体代码如下:

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. 再从右边快速找出三元组
    在这里插入图片描述

✔具体代码如下:

    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必须<right
                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题

✔解题思路:

在这里插入图片描述

✔具体代码如下:

    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题

✔解题思路:

在这里插入图片描述

✔具体代码如下:

    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型,但是我忘记后面也要强制转型了。我没有注意,导致我总是不知道我错哪里了,哭死我了!!!


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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

D. Star.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值