代码随想录力扣:数组1-6个人总结

704.二分查找

题目

        给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1

代码

class Solution {
    public int search(int[] nums, int target) {
        int left, right, mid;
        left = 0;
        right = nums.length - 1;
        while(left <= right){
            mid = left + (right -left) / 2;
            if(nums[mid] > target){
                right = mid - 1;
            }
            else if(nums[mid] < target){
                left = mid + 1;
            }
            else {
                return mid;
            }
        }
        return -1;

    }
}

总结

1.原理:左指针left和右指针right包住数组的头尾,循环判断目标target和mid值的大小,如果mid大,说明target在区间右边,令right右移,如果mid小,说明targer在区间左边,令left左移,直到循环终止。

2.核心算法(左闭右闭):while(left <= right)是循环条件 ,right =mid-1,left = mid +1。为什么循环条件的有等号,因为当left==right时,当前的元素其实还没有和target做过比较,因此也要进入while循环。

3.JAVA语法错误:nums.length 注意语法,后边没有()

4.代码错误:right = nums.length-1,因为是右闭区间这个-1不要漏掉。最后不要忘了如果找不到要返回-1。

刷题第二次总结

1.判断nums[mid]和target的大小时,想清楚哪个才是我们要的目标区间,不要写反了。

2.while(left <= right)是循环条件,这个等号还是要举个例子理解,不能死记硬背。

27.移除元素

题目

        给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组

代码

class Solution {
    public int removeElement(int[] nums, int val) {
        int i, j;
        i = 0;
        for(j = 0;j < nums.length;j++){
            if(nums[j] != val){
                nums[i++] = nums[j];
            }
        }
        return i;
    }
}

总结

(1)原理:两个指针,快指针进行遍历,用于判断当前元素是否等于val,慢指针用于指向当前更新元素位置的下标在哪里,所以如果当前元素是val,就让快指针继续往后走,如果当前元素不是val,就要把当前元素放到慢指针的下标位置,同时其++,最后返回i,因为最后一次++,正好等于长度。

刷题第二次总结

1.一定理解并想清楚快慢指针的作用,slow指向的是要插入新元素的下标位置,fast指向的是我们需要的元素位置,这样后边的return slow才能理解到位。

2.函数要返回修改后的数组长度,这里不能用length函数,因为数组只是数值被修改了,长度并没有变化,这里要返回slow,因为slow是要插入新元素的下标位置,正好等于新的length。

997.有序数组的平方

题目

        给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

代码

class Solution {
    public int[] sortedSquares(int[] nums) {
        int i, j, k; 
        int[] result = new int[nums.length];
        k = nums.length - 1;
        for(i = 0,j = nums.length-1;i <= j;){
            if(nums[i] * nums[i] > nums[j] * nums[j]){
                result[k--] = nums[i] *nums[i];
                i++;
            }
            else{
                result[k--] = nums[j] *nums[j];
                j--;
            }
        }
        return result;

    }
}

总结

(1)原理:左指针从头开始,右指针从尾开始,向中间靠近,判断哪个的平方更大,就往结果数组里面存,如果左更大,左指针++,如果右更大,右指针--,循环终止条件是<=,有等于是因为,左右指针相同的时候,还有最后一个元素没有存到结果数组里。

(2)语法问题:int[] result = new int[nums.length];用于开辟一个长度的数据,用来存储平方后的数组,这次这里没写出来。

(3)注意点:最后要return 结果数组,不要忘记了

刷题第二次总结

1.循环终止的条件要连接好,i和j指向的是没有存过平方数的下标,i<j时还有两个数没存呢,所以i=j时,还要存最后一个数的平方

2.这里的空间复杂度至少是O(n),必须要开辟一个result数组,想把平方后的数直接存在原数组是不行的,因为平方数数组是从后往前存的,而原数组右边的数可能还没被访问到就被覆盖了。

209.长度最小的子数组

题目

        给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组[numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度如果不存在符合条件的子数组,返回 0 。

代码

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int i, j, sum, sublength, result;
        i = j = sum = sublength = 0;
        result = Integer.MAX_VALUE;
        for(j = 0 ; j < nums.length ;j++){
            sum += nums[j];
            while(sum >= target){
                sublength = j - i + 1;
                result = result < sublength ? result : sublength;
                sum -= nums[i];
                i++;
                
            }
        }
        if(result == Integer.MAX_VALUE){
            return 0;
        }
        return result;
    }
}

总结

(1)原理:找满足和大于等于目标s的最小连续区间长度,用j遍历数组,表示窗口的左区间,用i表示窗口的右区间,如果窗口的元素和不足s,j就要一直++,让窗口变大,一旦窗口和满足s,就计算当前窗口大小,保存最小的窗口长度。注意,while(sum>=target),这里是while不是if,只要当前的滑动窗口值满足s,i就要一直右移找到直到不满足s,然后再调整j。

(2)语法错误:result = Integer.MAX_VALUE不会写,表示最大的int整数。

(3)算法错误:sum -= nums[i]; i++;这里出错了,因为要把滑动窗口元素和减去开始的值,i才能移动,这里两个语句的顺序不能换,一定要先把sum里面第i个元素减去,才能把滑动窗口i++。j < nums.length,这个length不用减1,因为是小于。

(4)注意,返回长度的时候多一次判断,如果result不变就是初始状态,就说明不存在满足s的区间,要return0,这个不要漏掉了。

刷题第二次总结

1.这一次的代码写的不太一样,就再放一次吧。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int i = 0;
        int j = 0;
        int sum = 0;
        int result = nums.length + 1;
        while(j < nums.length){
            sum += nums[j];
            while(sum >= target){
                result = result < j - i + 1 ? result : j - i + 1;
                sum -= nums[i];
                i++;
            }
            j++;
        }
        return result == nums.length + 1 ? 0 : result;
    }
}

2.result的初始值必须是一个较大数,由于Integer.MAX_VALUE容易记不住,result也可以用num.length + 1。原因如下,因为如果能找到满足序列,长度肯定是一个小于等于num.length的整数,直接返回。如果没找到,sum永远不可能大于target,result压根没有被修改还是等于num.length + 1,这时候return 0就行。

3.再说一下代码的逻辑,核心是对滑动窗口i和j的作用。

        第一个循环可以用while,也可以用for,区别就是j++的位置而言。第一个循环用于j对nums进行遍历,不断寻找满足sum>=target的区间。

        第二个while循环,这个就要好好理解一下了。这里千万不能写成if,因为我们要的是满足条件的最短区间。举个例子,前一个满足target=7的区间是2134,这里result是4,然后我们让i++,区间变成134,这里sum仍然满足7,如果用if,这一段区间就会错算出3,然后j就会继续往后走了。而我们要的是最短区间34。当134满足7的时候,i还有继续++缩小区间为34才行。

        核心就是要好好理解i和j到底是如何移动确定区间的,即j的作用就是一直向后搜索,帮我们扩大区间,直到满足7。这时,需要判断当前从i-j的区间中,i最多移动到哪。而i需要缩小到正好满足7的最小区间,如果i不用while移动,i可能找到的就不是最小区间了。

59.螺旋矩阵II

题目

        给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

代码

class Solution {
    public int[][] generateMatrix(int n) {
        int startx = 0;
        int starty = 0;
        int count = 1;
        int offset = 1;
        int loop = n / 2;
        int[][] martrix = new int[n][n];
        while(loop-- > 0){
            int i = startx;
            int j = starty;
            for(;j < n - offset;j++){
                martrix[i][j] = count++;
            }
            for(;i < n - offset;i++){
                martrix[i][j] = count++;
            }
            for(;j > starty;j--){
                martrix[i][j] = count++;
            }
            for(;i > startx;i--){
                martrix[i][j] = count++;
            }
            startx++;
            starty++;
            offset++;
        }
        if(n % 2 == 1){
            martrix[n/2][n/2] = count;
        }
        return martrix;
    }
}

总结

(1)原理:n*n矩阵,要走n/2圈,用startx和starty表示每一圈的起始位置,每走完一圈start要++,offset是多余的边界,每一圈结束也要++,再根据左闭右开,进行四个for循环,注意for(i),如果i不用赋值,就不要写i了,会报错。直接不写就行。

(2)语法错误:二维数组是这样定义的int[][] martix = new int[n][n];

(3)语法错误:while(loop--)不能这样写会编译出错,说int和boolen有问题,要写成while(loop-- > 0)才行

(4)注意:如果n是奇数,那么最后要把n/2的元素继续放count++;count++表示的是count增1,但是整个式子大小不变,所以初始count=1

刷题第二次总结

1.核心就是loop,offset,startx,starty参数,以及四个for循环的区间想明白就行。

2.几个参数的功能和初始化如下:

        loop表示参数,loop=n/2,循环条件是loop>0

        offset表示每一圈的边界宽度,左闭右开,初始边界长度=1,然后每一圈结束,要++。

        startx和starty表示每一圈的起始位置,初始值=0,然后每一圈结束,要++。

3.四个for循环的区间如下设置:

        第一个:j从starty到n-offset,for(;j < n - offset;j++)

        第二个:i从statyx到n-offset, for(;i < n - offset;i++)

        第三个:j从第一个for的结束位置到starty,for(;j > starty;j--)

        第四个:i从第二个for的结束位置到startx,for(;i > startx;i--)

PS:个人的学习方法

        先看代码随想录的文字学习理解,再看对应的b站视频加深理解。把3-5题的内容完成后,在leetcode上一起刷,如果运行出错了,在对应提交的备注里面写上自己不会的点。第二天复习的时候,不看任何资料前,打开leetcode直接手撕,如果一次性通过就没事,如果还有什么错误,继续在提交的备注里写不会的点。最后,把这两次的出错点+解题原理在CDSN进行。

        刷题第二次,一般就是直接看题目,在纸上理一下思路,一般都有思路的,然后就直接去力扣上写。没有思路的话,就可能当时第一遍根本没学好,可能需要再看一下代码随想录网站的笔记了。力扣上把代码写了,若没有运行不出错就来博客这边看一下笔记+理一下核心的算法思路。如果运行还出错,可能是算法的细节也可能是语法问题,就到博客整理出错误点+理一下核心的算法思路。这一轮基本上要更加理解题目的解题思路和算法逻辑了。第一轮的时候,可能写的代码和代码随想录基本一样,因为是学别人的思路写的,这一轮可能写的就是自己理解的成果了,如果两次代码出入比较大的话,这边我也会更新第二版的代码。

  • 23
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

守岁白驹hh

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

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

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

打赏作者

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

抵扣说明:

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

余额充值