力扣爆刷第162天之TOP100五连刷76-80(最小路径和、最长公共前缀、最长连续序列)
文章目录
- 力扣爆刷第162天之TOP100五连刷76-80(最小路径和、最长公共前缀、最长连续序列)
- 一、64. 最小路径和
- 二、221. 最大正方形
- 三、162. 寻找峰值
- 四、14. 最长公共前缀
- 五、128. 最长连续序列
一、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;
}
}