Leetcode 51-60刷题笔记(非困难题目)

53.最大子序和

该题目主要的思考就是在遍历数组时候是否考虑加上前面数组。

例如样例 [-2,1,-3,4,-1,2,1,-5,4]

我们从 下标 1 开始遍历,此时prev数组 = -2,那么此时我们如果将 -2 加入子数组中那么会导致综合减少(因为prev数组和 < 0),所以此时应当将 1 作为新子数组的头部,继续向后遍历(此时需要记录最大子数组和的值)

    //最大子数组和
    public int maxSubArray(int[] nums) {
        if(nums.length == 0) {
            return 0;
        }
        int prev = nums[0];
        int ans = nums[0];

        for(int i=1; i<nums.length; i++) {
            if(ans < 0) {
                prev = nums[i];
            }else {
                prev += nums[i];
            }
            ans = Math.max(ans,prev);
        }

        return ans;
    }

54.螺旋矩阵

该题目使用的是模拟法,我们通过模拟走路的形式,就是需要标记一个方向即可,并且在到达临界时候更改方向。

	//模拟法
    public List<Integer> spiralOrder(int[][] matrix) {
        List<Integer> order = new ArrayList<Integer>();
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return order;
        }
        int rows = matrix.length, columns = matrix[0].length;
        boolean[][] visited = new boolean[rows][columns];
        int total = rows * columns;
        int row = 0, column = 0;
        int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
        int directionIndex = 0;
        for (int i = 0; i < total; i++) {
            order.add(matrix[row][column]);
            visited[row][column] = true;
            //计算可能下一步的位置
            int nextRow = row + directions[directionIndex][0], nextColumn = column + directions[directionIndex][1];
            //下一步越界,更改方向
            if (nextRow < 0 || nextRow >= rows || nextColumn < 0 || nextColumn >= columns || visited[nextRow][nextColumn]) {
                directionIndex = (directionIndex + 1) % 4;
            }
            //计算真实下一步的位置
            row += directions[directionIndex][0];
            column += directions[directionIndex][1];
        }
        return order;
    }

55.跳跃游戏

该题目我是通过记录一个最远到达的位置,通过搜索能够到达的最远位置内的点,然后不断更新最远距离,一旦能够到达的最远距离超过最后一位,则说明成功。

    //跳跃游戏
    public boolean canJump(int[] nums) {
        //记录当前能到达的最远的点(换句话说也代表之前的点都可以到达)
        int rightMost = 0;
        for(int i=0; i<nums.length; i++) {
            //在所有能够到达的点中尝试更新能够到达的最远的点
            if(i <= rightMost) {
                rightMost = Math.max(rightMost,i+nums[i]);
            }
            //如果能够到达的最远距离超过最后一位,说明成功
            if(rightMost >= nums.length - 1) {
                return true;
            }
        }
        
        return false;
    }

56.合并区间

该题目需要注意的就是先排序后再分情况讨论。

这里为什么需要排序呢?

如果不排序的话,那么我们就无法确认这个混乱的区间集合如何进行合并,所以这里的我采用的是对做区间进行升序排序,这样可以保证当需要分割出新的区间时,我们可以判断出来(即下一位区间的左边界 > 当前区间的右边界)

排序后一共有三种情况,我在代码的注解中有写到。

在这里插入代码片    public int[][] merge(int[][] intervals) {
        Arrays.sort(intervals,(o1,o2) -> {return o1[0] - o2[0];});
        /*
        1.下一个数组的左边界 > 当前数组的右边界。此时需要将当前数组插入List,并更换当前数组
        2.下一位数组的左边界 <= 当前数组的右边界。
            2.1 下一位数组的右边界 > 当前数组的右边界。更新当前数组右边界
            2.2 下一位数组的右边界 <= 当前数组右边界。(包含关系)不做处理
         */
        List<int[]> list = new ArrayList<>();
        int left = -1;
        int right = left;

        for(int[] interval : intervals) {
            //初次访问
            if(left == -1) {
                left = interval[0];
                right = interval[1];
                continue;
            }
            //情况 1
            if(interval[0] > right) {
                list.add(new int[]{left,right});

                left = interval[0];
                right = interval[1];
            }else {
                if(interval[1] > right) { //情况 2.1
                    right = interval[1];
                }else { //情况 2.2(不作处理)

                }
            }
        }
        //最后还会剩下一个组合,需要记得添加进去
        list.add(new int[]{left,right});

        int[][] ans = new int[list.size()][2];

        for(int i=0; i<ans.length; i++) {
            ans[i] = list.get(i);
        }

        return ans;
    }

58.最后一个单词长度

该题比较简单,你可以正序遍历也可以反序遍历。

不管怎么样都是o(n)时间复杂度。

反序遍历就是当找到第一个非空字符开始记录,直到碰到空格为止,

下面代码我是用正序遍历,思路类似(不过正序稍微考虑的多点)

    public int lengthOfLastWord(String s) {
        //去除开头的空格
        s = s.trim();

        if(s.length() == 0) {
            return 0;
        }

        //记录单词起始和结尾
        int len = 0;
        //用于标记是否经过一个完整的单词
        boolean flag = false;
        for(int i=0; i<s.length(); i++) {
            if(s.charAt(i) == ' ') {
                flag = true;
            }else {
                if(flag) {
                    len = 1;
                    flag = false;
                }else {
                    len++;
                }
            }
        }

        return len;
    }

59.螺旋矩阵2

该题和54一样的,也是使用模拟法,模拟走路的方式就行了。

上个题目我是直接使用后面题解,下面我就自己写个带注解的版本。

    public int[][] generateMatrix(int n) {
        int[][] directions = {
                {0,1}, //向右
                {1,0}, //向下
                {0,-1},//向左
                {-1,0} //向上
        };

        //用于判断是否被访问过/添加过
        boolean[][] isVisit = new boolean[n][n];
        int[][] ans = new int[n][n];
        //标记方向
        int index = 0;
        int row = 0;
        int col = 0;
        int num = 1;
        
        for(int i=0; i<n*n; i++) {
            ans[row][col] = num++;
            //标记
            isVisit[row][col] = true;
            //获得当前前进方向
            int[] direction = directions[index % 4];
            
            int nextRow = row +  direction[0];
            int nextCol = col + direction[1];
            if(nextCol >= n || nextCol < 0 || nextRow >= n || nextRow < 0 || isVisit[nextRow][nextCol]) {
                //改变方向
                index++;
                direction = directions[index % 4];
            }
            row += direction[0];
            col += direction[1];
        }

        return ans;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值