最小路径和: 64
64. 最小路径和 - 力扣(LeetCode) (leetcode-cn.com)
给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例 1:
输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。
示例 2:
输入:grid = [[1,2,3],[4,5,6]]
输出:12
题解:
dp[ i ] [ j ] 当前位置 向下或者向右 走 也就是说 从它的左边或者上边过来的。要最优解 也就是左边或者上边的最小值 + 上自己当前的。
数组第一行 只能依赖左边的数据 因为它没有上一行
数组第一列 只能依赖上边的数据 因为它没有左一列
public int minPathSum(int[][] grid) {
if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) {
return 0;
}
int row = grid.length;
int col = grid[0].length;
int[][] dp = new int[row][col];
dp[0][0] = grid[0][0];
for (int i = 1; i < row; i++) {
dp[i][0] = dp[i - 1][0] + grid[i][0];
}
for (int j = 1; j < col; j++) {
dp[0][j] = dp[0][j - 1] + grid[0][j];
}
for (int i = 1; i < row; i++) {
for (int j = 1; j < col; j++) {
dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
}
}
return dp[row - 1][col - 1];
}
此方法 需要 创建 grid的小的 一个 dp表
dp[ i ] [ j ] 只依赖它的 左 和它的上 省空间
准备 一个数组 直接在这个数组上 进行 自我更新!(按照数组 说的行 个)
第0 行 只依赖左 可以直接完成第一行, 第1行的 第一个数据 是依赖0行的 第一个 无左 下一个数据 需要的是左和上的数据 因为 1行第0个可以直接根据 0行0个 来进行更新, 所以 1 1的值 的左侧上边,选出小的就可以 自我更新。
public int minPathSum(int[][] grid) {
if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0){
return 0;
}
int row = grid.length;
int col = grid[0].length;
int[] dp = new int[col];
dp[0] = grid[0][0];
for (int j = 1; j < col; j++) {
dp[j] = dp[j - 1] + grid[0][j];
}
for (int i = 1; i < row; i++) {
dp[0] += grid[i][0];
for (int j = 1; j < col; j++) {
dp[j] = Math.min(dp[j], dp[j - 1]) + grid[i][j];
}
}
return dp[col - 1];
}
只出现一次的数字Ⅲ 260
260. 只出现一次的数字 III - 力扣(LeetCode) (leetcode-cn.com)
给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。
进阶:你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?
示例 1:
输入:nums = [1,2,1,3,2,5]
输出:[3,5]
解释:[5, 3] 也是有效的答案。
示例 2:
输入:nums = [-1,0]
输出:[-1,0]
示例 3:
输入:nums = [0,1]
输出:[1,0]
提示:
2 <= nums.length <= 3 * 104
-231 <= nums[i] <= 231 - 1
除两个只出现一次的整数外,nums 中的其他数字都出现两次
题解:异或运算,只有两个元素出现一次。
在异或中 a^a =0, 所有 整个数组 异或最后的结果就是 只出现一次的两个元素的异或结果。
取出最右侧的1 因为两个数异或
1001100
^ 0101010
1100110 取出最右侧的1 之后 就肯定会得到其中的一个 , 在与整个数组异或的结果异或 就能得到另一个。
public int[] singleNumber(int[] nums) {
int eor=0;
for(int i =0; i < nums.length; i++){
eor^=nums[i];
}
int right = eor & (-eor);
int other = 0;
for(int i = 0; i< nums.length; i++){
if((nums[i] & right) != 0 ){
other^=nums[i];
}
}
return new int[]{other,other^eor};
}
滑动窗口最大值 239
239. 滑动窗口最大值 - 力扣(LeetCode) (leetcode-cn.com)
暴力解…就每个新的拿出最大值。好像是超出时间限制
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums == null || k < 1 || nums.length < k) {
return null;
}
int N = nums.length;
int[] res = new int[N - k + 1];
int index = 0;
int L = 0;
int R = k - 1;
while (R < N) {
int max = nums[L];
for (int i = L + 1; i <= R; i++) {
max = Math.max(max, nums[i]);
}
res[index++] = max;
L++;
R++;
}
return res;
}
- 准备队列 按照大到小存放数据。 队列存 的是下标。在来到新的值的时候 需要与队列的进行判断 如果新到来的小直接放在尾部
如果大,队列尾部扔掉不要,在比较大接着扔掉不要 直到新来的数找到位置。加入到队列的尾部。
此题窗口为3, 在窗口移动时,需要去判断 队列中的数 还可不可以用(是不是在窗口范围内) ,如果不在 扔掉它。R-K是不在窗口内的下标。
当R >= k-1 形成窗口 的时候拿出当前的最大值就是队列的first
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums == null || k < 1 || nums.length < k) {
return null;
}
LinkedList<Integer> lMax = new LinkedList<>();
int[] res = new int[nums.length - k + 1];
int index = 0;
for(int R =0; R < nums.length; R++){
while(!lMax.isEmpty() && nums[lMax.peekLast()] <= nums[R]){
lMax.pollLast();
}
lMax.addLast(R);
if(lMax.peekFirst() == R-k){
lMax.pollFirst();
}
if(R >= k-1){
res[index++] = nums[lMax.peekFirst()];
}
}
return res;
}
柱状图中最大矩形 84
84. 柱状图中最大的矩形 - 力扣(LeetCode) (leetcode-cn.com)
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10
输入: heights = [2,4]
输出: 4
解题:以index 的值 为高 能扩多远 扩出来的个数*自己 枚举每一个高求出最好的答案
public int largestRectangleArea(int[] heights) {
if (heights == null || heights.length == 0) {
return 0;
}
int maxArea = 0;
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < heights.length; i++) {
while (!stack.isEmpty() && heights[i] <= heights[stack.peek()]) {
int j = stack.pop();
int k = stack.isEmpty() ? -1 : stack.peek();
int curArea = heights[j] * (i - k - 1);
maxArea = Math.max(curArea, maxArea);
}
stack.push(i);
}
while (!stack.isEmpty()) {
int j = stack.pop();
int k = stack.isEmpty() ? -1 : stack.peek();
int curArea = heights[j] * (heights.length - k - 1);
maxArea = Math.max(curArea, maxArea);
}
return maxArea;
}
最大矩形85
85. 最大矩形 - 力扣(LeetCode) (leetcode-cn.com)
给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
示例 1:
输入:matrix = [[“1”,“0”,“1”,“0”,“0”],[“1”,“0”,“1”,“1”,“1”],[“1”,“1”,“1”,“1”,“1”],[“1”,“0”,“0”,“1”,“0”]]
输出:6
解释:最大矩形如上图所示。
示例 2:
输入:matrix = []
输出:0
示例 3:
输入:matrix = [[“0”]]
输出:0
示例 4:
输入:matrix = [[“1”]]
输出:1
示例 5:
输入:matrix = [[“0”,“0”]]
输出:0
解题:压缩数组 + 单调栈
以 第0行作底 1行做底… 有0高度归0 n 行 每一行按照高度扩 求出最大值
[1,1,1,0,1,1] [1,1,1,0,1,1]
[0,1,0,1,0,0] [0,2,0,1,0,0]
[1,1,1,1,0,1] -> [1,3,1,2,0,1]
[1,1,1,1,0,0] [2,4,2,3,0,0]
public int maximalRectangle(char[][] matrix) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return 0;
}
int maxArea = 0;
int[] height = new int[matrix[0].length];
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
height[j] = matrix[i][j] == '0' ? 0 : height[j] + 1;
}
maxArea = Math.max(MaximumValuePerLine(height), maxArea);
}
return maxArea;
}
public static int MaximumValuePerLine(int[] height) {
if (height == null || height.length == 0) {
return 0;
}
int maxArea = 0;
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < height.length; i++) {
while (!stack.isEmpty() && height[i] <= height[stack.peek()]) {
int j = stack.pop();
int k = stack.isEmpty() ? -1 : stack.peek();
int curArea = height[j] * (i - k - 1);
maxArea = Math.max(curArea, maxArea);
}
stack.push(i);
}
while (!stack.isEmpty()) {
int j = stack.pop();
int k = stack.isEmpty() ? -1 : stack.peek();
int curArea = height[j] * (height.length - k - 1);
maxArea = Math.max(curArea, maxArea);
}
return maxArea;
}