力扣爆刷第162天之TOP100五连刷76-80(最小路径和、最长公共前缀、最长连续序列)

力扣爆刷第162天之TOP100五连刷76-80(最小路径和、最长公共前缀、最长连续序列)

一、64. 最小路径和

题目链接:https://leetcode.cn/problems/minimum-path-sum/description/
思路:每次只能向下或向右移动一步,求最小路径和,很经典的一道动态规划题,定义dp[i][j]表示,抵达nums[i][j]时的最小路径和,那么根据定义,要想抵达nums[i][j]这个位置,就得从nums[i-1][j]或者nums[i][j-1]的位置出发,而这两个位置对应的最小路径和即为dp[i-1][j]或者dp[i][j-1],故而dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + nums[i][j]。
另外就是可以节省一下空间,把二维数组替换成一维数组。那么就要注意初始化,以及每一行开始的位置。
在这里插入图片描述

class Solution {
    public int minPathSum(int[][] grid) {
        int m = grid.length, n = grid[0].length;
        int[] dp = new int[n+1];
        Arrays.fill(dp, Integer.MAX_VALUE);
        dp[1] = 0;
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                dp[j+1] = Math.min(dp[j], dp[j+1]) + grid[i][j];
            }
        }
        return dp[n];
    }
}

二、221. 最大正方形

题目链接:https://leetcode.cn/problems/maximal-square/description/
思路:矩阵内包含0或者1,求全为1的最大正方形,其实可以把题目理解为不为零的正方形的边长的计算,定义dp[i][j]表示以nums[i][j]为右下角的不为0的正方形的最大边长。那么根据定义可以得到推导关系,如果nums[i][j]不为0,那么以他为右下角的不为0的最长正方形边长,应该依赖于该位置的左方、上方、左上方的最小边长+1,。如这3个位置记录的边长为1,1,0,那么此处为0+1,如果是1,1,1,那么此处为1+1。如果为1,2,1,那么此处为1+1.
故而,dp[i][j] = Math.min(dp[i-1][j-1], Math.min(dp[i-1][j], dp[i][j-1])) + 1;
在这里插入图片描述

class Solution {
    public int maximalSquare(char[][] matrix) {
        int m = matrix.length, n = matrix[0].length;
        int[][] dp = new int[m][n];
        int max = 0;
        for(int i = 0; i < m; i++) {
            for(int j =0; j < n; j++) {
                if(matrix[i][j] == '0') continue;
                else if(i == 0 || j == 0) dp[i][j] = 1;
                else dp[i][j] = Math.min(dp[i-1][j-1], Math.min(dp[i-1][j], dp[i][j-1])) + 1;
                max = Math.max(max, dp[i][j]);
            }
        }
        return max * max;
    }
}

三、162. 寻找峰值

题目链接:https://leetcode.cn/problems/find-peak-element/description/
思路:让在数组中寻找峰值,所谓峰值即1,2,1其中2就是峰值,本身来说好找,遍历一遍即可,但是题目要求在O(logn)的时间复杂度完成,那么一般只要是要求logn,那么基本上就得是划分区间二分之类的,才能达到,心里要有这个意识。
既然知道了需要划分区间,那么区间该如何划分呢?其实很简单就是二分划分,二分查找,中间值如果满足峰值条件就直接返回,如果不满足就再次划分区间去各自的区间内进行重复的寻找即可。

class Solution {
    int index = -1;
    public int findPeakElement(int[] nums) {
        if(nums.length == 1) return 0;
        findMax(nums, 0, nums.length-1);
        return index;
    }
    
    void findMax(int[] nums, int left, int right) {
        if(left > right || index != -1) return;
        int mid = left + (right - left) / 2;
        if(mid == 0) {
            if(nums[mid] > nums[mid+1]) {
                index = mid;
                return;
            }
        }else if(mid == nums.length-1) {
            if(nums[mid] > nums[mid-1]) {
                index = mid;
                return;
            }
        }else if(nums[mid] > nums[mid-1] && nums[mid] > nums[mid+1]) {
            index = mid;
            return;
        }
        findMax(nums, left, mid-1);
        findMax(nums, mid+1, right);
    }
}

四、14. 最长公共前缀

题目链接:https://leetcode.cn/problems/longest-common-prefix/description/
思路:求最长公共前缀,这个直接遍历就可以,用第一个字符串中的每一个字符去遍历剩下每一个字符串中的字符,只要出现长度超界或者不等,就算抵达终点位置了,直接返回即可。

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if(strs.length == 1) return strs[0];
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < strs[0].length(); i++) {
            for(int j = 1; j < strs.length; j++) {
                if(i >= strs[j].length() || strs[0].charAt(i) != strs[j].charAt(i)) return sb.toString();
            }
            sb.append(strs[0].charAt(i));
        }
        return sb.toString();
    }
}


五、128. 最长连续序列

题目链接:https://leetcode.cn/problems/longest-consecutive-sequence/description/
思路:有一个无序序列,求其中的元素能够排列组合成的最长连续序列,也就是如4,5,3,2,1,最长为1,2,3,4,5最长连续长度为5。
这种无序的请求可以考虑使用set添加元素,都添加之后遍历set,如果当前元素-1不存在于set之中,说明这个元素可能是一个连续序列的开头,所以就从此处开始,不断的+1,然后判断是否在set中,这样就可以求出最长连续序列。

class Solution {
    public int longestConsecutive(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for(int i : nums) set.add(i);
        int max = 0;
        for(int i : set) {
            if(!set.contains(i-1)) {
                int t = 0;
                while(set.contains(i)) {
                    i++;
                    t++;
                }
                max = Math.max(max, t);
            }
        }
        return max;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

当年拼却醉颜红

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

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

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

打赏作者

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

抵扣说明:

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

余额充值