微信平台微商城/优化外包服务公司
4.图
4.1.被围绕的区域
思路:图中只有与边界上联通的O才不算是被X包围。因此本题就是从边界上的O开始递归,找与边界O联通的O,并标记为#(代表已遍历),最后图中剩下的O就是:被X包围的O。图中所有 '#' 则是与边界O联通的情况
class Solution {public void solve(char[][] board) {for (int i = 0; i < board.length; i++) {for (int j = 0; j < board[0].length; j++) {if (i == 0 || j == 0 || i == board.length - 1 || j == board[0].length - 1) {//如果当前点在边界if (board[i][j] == 'O') {//当前点在边界,且当前点为Odfs(board, i, j);}}}}for (int i = 0; i < board.length; i++) {for (int j = 0; j < board[0].length; j++) {if (board[i][j] == 'O') {//说明当前点是不与边界O联通的O,说明当前O被X包围board[i][j] = 'X';//赋值为X}if (board[i][j] == '#') {//说明当前位置是O,但是是与边界O联通的Oboard[i][j] = 'O';//说明当前点不被X包围,重置为O}}}}//该方法用于找到所有与边界O联通的Opublic void dfs(char[][] board, int i, int j) {if (i < 0 || i > board.length - 1 || j < 0 || j > board[0].length - 1//如果当前点越界||board[i][j] == 'X' || board[i][j] == '#' //或者当前点不为O !) return;//直接返回board[i][j] = '#';//能到这一步说明当前点,是与边界O联通的O,标记为已遍历(防止死循环)//找与当前位置相邻的、与边界O联通的Odfs(board, i + 1, j);dfs(board, i - 1, j);dfs(board, i, j + 1);dfs(board, i, j - 1);}
}
5.贪心
5.1项目利润问题
贪心的题目思路不太好写,最主要就是贪心的一种感觉。如果要严格的数学证明,太麻烦了
本题思路:本题就是一个局部最优解到全局最优解的题。每次都在已经解锁 (当前手上有的钱大于某个项目的花费,该项目就算是被解锁)了的项目中选一个利润最大的项目。这样最后得到的就是最大的最终资本。要注意的是,每次做完一次项目,手头上的钱就变为:之前的钱+本次项目的利润。因此,每次做项目之前,都要更新一下被解锁的项目!
代码实现:
class Solution {public int findMaximizedCapital(int k, int w, int[] profits, int[] capital) {int[][] arr = new int[profits.length][2];//数组第一个元素为当前项目的最小资金,第二个元素为利润for (int i = 0; i < profits.length; i++) {arr[i][0] = capital[i];arr[i][1] = profits[i];}//用于存放每个项目花费的小根堆PriorityQueue<int[]> capitalQ = new PriorityQueue<>(new Comparator<int[]>() {@Overridepublic int compare(int[] arr1, int[] arr2) {return arr1[0] - arr2[0];}});//存放已经解锁的每个项目的利润的大根堆(每次都要已经解锁了,切利润最大的项目)PriorityQueue<int[]> profitsQ = new PriorityQueue<>(new Comparator<int[]>() {@Overridepublic int compare(int[] arr1, int[] arr2) {return arr2[1] - arr1[1];}});//全部项目都进入被锁的队列中for (int i = 0; i < arr.length; i++) {capitalQ.add(arr[i]);}for (int i = 0; i < k; i++) {//进行k轮//如果资金w大于当前项目的花费且花费队列不为空,该项目被解锁//这个while循环执行完以后,就会把当前所有能解锁的项目(当前手上的钱w > 项目花费 视为解锁)全部放入利润大根堆。while (!capitalQ.isEmpty() && capitalQ.peek()[0] <= w) {profitsQ.add(capitalQ.poll());//该项目被解锁,放入利润大根堆}if (profitsQ.isEmpty()) {//当我手上的钱不足以做接下来任何一个项目时,就会出现利润大根堆提前为空的情况return w;//提前返回现在所有的钱}//每次都从利润大根堆找出利润最高的项目w += profitsQ.poll()[1];}return w;}
}
6.递归回溯
6.1N皇后问题
class Solution {public int totalNQueens(int n) {if (n < 1) return 0;//代表:第i行的皇后,放在了第record[i]列int[] record = new int[n];return process(0, record, n);}/*** @param i 目前来到了第i行* @param record 之前已经摆好皇后的位置(潜台词:前面的皇后位置都不冲突!)* @param n 整体一共有多少行*/public int process(int i, int[] record, int n) {if (i == n) {//递归结束,前n个皇后都已经摆放好了位置return 1;//前n个皇后都已经摆好了位置,代表找到了一种摆法}int res = 0;for (int j = 0; j < n; j++) {//当前在第i行,遍历第i行的所有列,判断是否合法摆放。j代表列// 判断当前位置,是否可以摆放皇后if (isValid(record, i, j)) {record[i] = j;//当前位置可以摆放皇后//递归摆放接下来皇后的位置//当前行,尝试的所有位置做累加,就是当前情况(在record已经摆好的情况下,接下来所有合法情况的总数)res += process(i + 1, record, n);}}return res;}/*** 判断第i行的第i列,是否可以摆放皇后(是否和之前的皇后位置冲突)** @param record 之前已经摆放好皇后的位置* @param i 第i行* @param j 第i列* @return true:可以摆放到当前位置,不冲突。false:位置冲突*/private boolean isValid(int[] record, int i, int j) {for (int k = 0; k < i; k++) {//只有前k行皇后位置被摆放好,需要比较。遍历之前每个皇后的位置if (j == record[k]//如果和之前某个皇后同一列|| //或者Math.abs(record[k] - j) == Math.abs(i - k)//当前位置和之前某一个皇后位置在同一列(横坐标之差绝对值=纵坐标之差绝对值)) {return false;}}return true;}
}
6.2经典汉诺塔问题
这类问题,只要把握住局部情况,每次的局部情况符合要求,整体情况就不会出错。
比如说:当前A中有i个盘
1.先把上面i-1个盘,从A经过C,移动到B。把第i个盘空出来(因为大盘不能叠在小盘上)。
2.现在第i个盘空出来了,可以直接从A移动到C。
3.最后把上面i-1个盘,从B经过A移动到C。
这样当A中有i个盘的情况就完成了。
如果我每次移动都遵守这个规律,每次要移动大盘的时候,就把上面的小盘全部移都,把大盘空出来,这次移动就保证了大盘一定不会叠着小盘,且大盘在小盘下。整体情况,就一定也会满足这个要求。
这类递归题目不好理解。对于尝试的时候,我们没必要想着全局情况是怎么样变化的。而是应该定义一个统一的标准,每次局部都满足这个情况。整体一定也满足!
总的来说,我们不应该想着全局如何变化。应该想在当前局部情况我们应该怎么样拆解问题,只要局部拆解问题对了,决策对了。整体也就对了。
还有一点要注意的就是,我们拆解问题,拆到最后一定有一个拆不了的情况。比如说本题就是,当A中只有一个盘的情况,就可以直接移动了。这就是递归的终止条件!
public void hanota(List<Integer> A, List<Integer> B, List<Integer> C) {func(A.size(), A, B, C);}/*** 当前A中有1~i个圆盘,把最下面一个圆盘,从A经过B,移动到C** @param i 圆盘数量* @param A 移动起始位置* @param B 经过位置* @param C 目标位置*/public void func(int i, List<Integer> A, List<Integer> B, List<Integer> C) {if (i == 1) {//当A中只有一个元素了(一定是最小的),直接从A移动到CC.add(A.remove(1));}//先把A上面i - 1个圆盘从A经过C移动到B。func(A.size() - 1, A, C, B);//再把第i个圆盘从A移动到C,因为此时i-1个圆盘全部在B,可以直接移动C.add(A.remove(i));//再把i - 1个圆盘从B移动回Afunc(A.size() - 1, B, C, A);}
6.3.岛屿数量
本题借鉴了leetcode大佬的思路,讲的非常清晰!
. - 力扣(LeetCode)
class Solution {public int numIslands(char[][] grid) {int res = 0;for (int i = 0; i < grid.length; i++) {for (int j = 0; j < grid[0].length; j++) {if (grid[i][j] == '1') {//如果当前位置是一个岛屿dfs(grid, i, j);res++;}}}return res;}public void dfs(char[][] grid, int r, int c) {//当前元素在第r行,第c列if (!inArea(grid, r, c)) return;//如果当前位置越界了,直接返回if (grid[r][c] != '1') return;//如果当前位置不是岛屿,直接返回//能走到这,说明当前位置没遍历过,且是岛屿grid[r][c] = '2';//当前位置标记为已遍历// 访问上、下、左、右四个相邻结点dfs(grid, r - 1, c);dfs(grid, r + 1, c);dfs(grid, r, c - 1);dfs(grid, r, c + 1);}public boolean inArea(char[][] grid, int r, int c) {//判断当前位置是否越界,true 代表没越界return r >= 0 && r < grid.length && c >= 0 && c < grid[0].length;}
}
6.4.岛屿最大面积
本题大致思路和上一题差不多。
class Solution {public int maxAreaOfIsland(int[][] grid) {int max = 0;for (int i = 0; i < grid.length; i++) {for (int j = 0; j < grid[0].length; j++) {max = Math.max(max, dfs(grid, i, j));}}return max;}public int dfs(int[][] grid, int r, int c) {if (!inArea(grid, r, c)) return 0;if (grid[r][c] != 1) return 0;grid[r][c] = 2; // 标记为已遍历return 1 + dfs(grid, r, c - 1) +//当前岛屿的面积等于:当前位置就是一个岛屿面积为1 + 上下左右方岛屿面积之和dfs(grid, r, c + 1) +dfs(grid, r - 1, c) +dfs(grid, r + 1, c);}public boolean inArea(int[][] grid, int r, int c) {return r >= 0 && r < grid.length && c >= 0 && c < grid[0].length;}
}
6.5.岛屿周长
本题思路与上面类似,就是注意base case的判断
class Solution {public int islandPerimeter(int[][] grid) {int max = 0;for (int i = 0; i < grid.length; i++) {for (int j = 0; j < grid[0].length; j++) {if (grid[i][j] == 1) return dfs(grid, i, j);}}return 0;}public int dfs(int[][] grid, int r, int c) {// 函数因为「坐标 (r, c) 超出网格范围」返回,对应一条越界的边if (!inArea(grid, r, c)) {return 1;}// 函数因为「当前格子是海洋格子」返回,对应一条与海洋相邻的边if (grid[r][c] == 0) {return 1;}// 函数因为「当前格子是已遍历的陆地格子」返回,和周长没关系if (grid[r][c] != 1) {return 0;}grid[r][c] = 2;return dfs(grid, r, c - 1) +//当前岛屿的周长等于:上下左右方岛屿面积之和dfs(grid, r, c + 1) +dfs(grid, r - 1, c) +dfs(grid, r + 1, c);}public boolean inArea(int[][] grid, int r, int c) {return r >= 0 && r < grid.length && c >= 0 && c < grid[0].length;}
}
6.6.预测赢家(博弈)
public boolean predictTheWinner(int[] nums) {// 返回我先手能获取的最大值,和后手获取的最大值return a(nums, 0, nums.length - 1) >= b(nums, 0, nums.length - 1);}//来到当前位置,还剩第l个元素到第r个元素没有选,我先选public int a(int[] arr, int l, int r) {if (l == r) {//如果只剩一个元素了,还是我先选return arr[l];}return Math.max(arr[l] + b(arr, l + 1, r),//选了第l个元素,那么接下来我就是后手了arr[r] + b(arr, l, r - 1)//选了第r个元素,接下来我也是后手 且选择元素范围也改变了);}//来到当前位置,还剩第l个元素到第r个元素没有选,我后手//注意:当前不是我拿,是对方先手在l到r范围上拿public int b(int[] arr, int l, int r) {if (l == r) {//当前最后只有最后一个元素,我还是后手,肯定就被对手选了return 0;//返回0,没有元素选了}//注意:这里可能不好理解为什么是min//这两种情况是:对手做完,我是后手情况,被迫接受的!所以就是最差情况min//因为这是二人博弈,对手先手选的是最大的值,轮到后手的我,选的只会是最小的值。//对手选的分多,我的分就少了。下回合轮到我先手也是同理,对手分就少了return Math.min(//注意当前是我在等待对方先手在l到r范围上拿,我没得拿!a(arr, l + 1, r),a(arr, l, r - 1));}
7.动态规划
7.1.买卖股票的最佳时期1
思路:动态规划问题,最重要的就是找到问题的状态。把问题状态不重不漏的划分出来。对于本题:每日的股票持有最大价值可以分为两种情况。
1.第i天我手上有股票的最大价值:两种情况,1.和我昨天有股票的情况一样。2.昨天没有股票,买当天的股票。
2.第i天我手上没有股票的最大价值:两种情况,1.和我昨天没有股票的情况一样。2.昨天有股票,当天卖了股票。
要注意的是:这里只能买一次股票。注意和下一题比较区分。
class Solution {public int maxProfit(int[] prices) {//dp[i][0]:代表第i天有股票(之前就有股票/当天买入)的最大利润//dp[i][1]:代表第i天没有股票(之前没有/当天卖了)的最大利润int[][] dp = new int[prices.length][2];dp[0][0] = -prices[0];dp[0][1] = 0;for(int i = 1; i < prices.length; i++){//dp[i][0]:代表第i天有股票(之前就有股票/当天买入)的最大利润 = 前一天的股票价值/前天没有,当天买入的最大值dp[i][0] = Math.max(dp[i-1][0],-prices[i]);dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0]+prices[i]);}return Math.max(dp[prices.length-1][0],dp[prices.length-1][1]);}
}
7.2.买卖股票的最佳时期2
大致思路和上一题差不多,但要区分这里可以进行多次股票买卖。
注意:这里的:dp[i-1][1]-prices[i] 就包含了多次买卖股票的情况。
class Solution {public int maxProfit(int[] prices) {//dp[i][0]:代表第i天有股票(之前就有股票/当天买入)的最大利润//dp[i][1]:代表第i天没有股票(之前没有/当天卖了)的最大利润int[][] dp = new int[prices.length][2];dp[0][0] = -prices[0];dp[0][1] = 0;for(int i = 1; i < prices.length; i++){//dp[i][0]:代表第i天有股票(之前就有股票/当天买入)的最大利润 = 前一天的股票价值/前天没有,当天买入的最大值dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]-prices[i]);dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0]+prices[i]);}return Math.max(dp[prices.length-1][0],dp[prices.length-1][1]);}
}
7.3.买卖股票的最佳时期3
class Solution {public int maxProfit(int[] prices) {// dp[i][0]: 第一次有股票 = Math.max(前天就有,买今天的) 注意买第i天股票就是 -prices[i]// dp[i][1]: 第一次卖完股票,不持有股票 = Math.max(前天没有,今天还有,当天卖) // dp[i][2]: 第二次有股票 = Math.max(前天就有,在第一次买卖完没有股票的基础上,买入今天股票)// dp[i][3]: 第二次卖完股票,不持有 = Math.max(前天就没有,今天是第二次有股票,当天卖)int[][] dp = new int[prices.length][4];dp[0][0] = -prices[0];dp[0][1] = 0;dp[0][2] = -prices[0];dp[0][3] = 0;for (int i = 1; i < prices.length; i++) {dp[i][0] = Math.max(dp[i - 1][0], -prices[i]);dp[i][1] = Math.max(dp[i - 1][1], dp[i][0] + prices[i]);dp[i][2] = Math.max(dp[i - 1][2], dp[i][1] - prices[i]);dp[i][3] = Math.max(dp[i - 1][3], dp[i][2] + prices[i]);}return dp[prices.length - 1][3];}
}
7.4.买卖股票的最佳时期4
7.5.买卖股票的最佳时期(含手续费)
7.6.买卖股票的最佳时期(含冷冻期)
7.7.打家劫舍
class Solution {public int rob(int[] nums) {if(nums.length == 1) return nums[0];if(nums.length < 3) return Math.max(nums[0],nums[1]);int[][] dp = new int[nums.length + 1][2];dp[1][0] = nums[0];dp[1][1] = 0;dp[2][0] = nums[1];dp[2][1] = nums[0];for(int i = 3; i <= nums.length; i++){//抢第i家能获取的最大金额dp[i][0] = Math.max(dp[i - 2][0],dp[i -1][1]) + nums[i -1];//不抢第i家dp[i][1] = Math.max(dp[i - 1][0],dp[i - 1][1]);}return Math.max(dp[nums.length][0],dp[nums.length][1]);}
}
7.7.打家劫舍III (树形dp)
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val = val; }* TreeNode(int val, TreeNode left, TreeNode right) {* this.val = val;* this.left = left;* this.right = right;* }* }*/
class Solution {public int rob(TreeNode root) {int[] process = process(root);return Math.max(process[0],process[1]);}//返回数组有两个元素,第一个元素代表偷当前节点的最大值,第二个元素为不偷当前节点的最大值public int[] process(TreeNode root) {if (root == null) return new int[]{0, 0};if (root.left == null && root.right == null) return new int[]{root.val, 0};int[] left = process(root.left);int[] right = process(root.right);//偷当前节点最大值 = 当前节点的值 + 不偷左右孩子int max1 = root.val + left[1] + right[1];//不偷当前节点 = 偷/不偷左孩子价值更大的一个 + 偷/不偷右孩子价值更大的一个 int max2 = Math.max(left[1], left[0]) + Math.max(right[0], right[1]);return new int[]{max1, max2};}
}
7.8.单词拆分
class Solution {public boolean wordBreak(String s, List<String> wordDict) {//把wordDict中的元素放到set集合中,方便后续判断有没有某个单词Set<String> set = new HashSet<String>(wordDict);//dp数组,dp[i] 代表字符串0到i,在不在set中,能不能被字典中的单词表示boolean[] dp = new boolean[s.length() + 1];dp[0] = true;for(int i = 1; i <= s.length(); i++){//遍历字符串sfor(int j = 0; j < i; j++){//判断从字符串0到i的长度,能不能被字典中的单词表示if(dp[j] && set.contains(s.substring(j, i))){//如果0到j能被表示,且j到i能被表示 (在字典中)dp[i] = true;//则0到i也能被表示break;}}}return dp[s.length()];}
}
7.9.零钱兑换(完全背包问题)
class Solution {public int coinChange(int[] coins, int amount) {// dp[i] 就代表凑齐 i 元所需要的硬币数量int[] dp = new int[amount + 1];Arrays.fill(dp, amount + 1);dp[0] = 0;for (int i = 1; i <= amount; i++) {for (int j = 0; j < coins.length; j++) {if (i >= coins[j]) {//当前遍历到第j个硬币,一共凑齐了i元//凑齐这i元最小硬币数:dp[i] 没有用当前硬币//用了当前硬币才凑齐的i元所用的硬币数:dp[i - coins[j]] + 1(当前硬币的数量)dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);}}}return dp[amount] == amount + 1 ? -1 : dp[amount];}
}
7.10.骑士在棋盘上的概率(三维dp)
左神第p18大概一小时左右讲了类似题目
class Solution {//用来代表每一对骑士的走法int[][] dirs = new int[][]{{-1,-2},{-1,2},{1,-2},{1,2},{-2,1},{-2,-1},{2,1},{2,-1}};public double knightProbability(int n, int k, int row, int column) {//一个三维dp数组,z方向代表剩余步数//x,y方向用来决定当前骑士的位置//如果dp[][][] = 1 代表骑士在棋盘里的概率double[][][] dp = new double[n][n][k + 1];for(int i = 0; i < n; i++){for(int j = 0; j < n; j++){dp[i][j][0] = 1;//剩余步数为0,棋盘中的每一个点都代表在棋盘里}}//每一层(z轴)都依赖于下一层的走法for(int h = 1; h <= k; h++){//遍历当前层的每一个点for(int i = 0; i < n; i++){for(int j = 0; j < n; j++){for(int[] d : dirs){//走完以后的位置int nx = i + d[0], ny = j + d[1];//如果越界了,就不进入概率计算if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue;//如果当前位置在棋盘里dp[i][j][h] += dp[nx][ny][h - 1] / 8;}}}}// 本题求从最下面一层的起始 x = row y = column 到达最上面一层合法区域的概率// 和,求从最上面的 x = row y = column 出发,达到最下面一层的合法区域的概率 是相同的!// 因此返回值为从最下面合法区域的任何一个点开始,到达最顶上 x = row y = column 的概率return dp[row][column][k];}
}
8.滑动窗口和单调栈
1.滑动窗口最大值
注意:每次从队尾添加一个数进队列,一定要跟在比它大的元素后面。如果队尾元素不满足比当前添加元素大,就一直弹出。直到满足队尾元素比它大,或者队列弹空了。
原理:窗口中维持的信息是:有可能成为最大值的下标。每次添加一个值,已经在队列中且比当前元素小的元素就再也不可能成为最大值了。因为,那些数比当前元素小,且当前元素比它们更晚被淘汰 (更晚出队列,因为从左往右遍历的,如果窗口左边界也移动,当前元素一定比那些元素更晚淘汰!)
class Solution {public int[] maxSlidingWindow(int[] nums, int k) {if (nums.length < k) {int max = Integer.MIN_VALUE;for (int num : nums) {max = Math.max(num, max);}return new int[]{max};}int l = -1;//窗口左边界int r = -1;//窗口右边界int index = 0;//存放答案的数组int[] res = new int[nums.length - k + 1];//双端队列,规则:队头元素始终是最大元素,队头到队尾由小到大LinkedList<Integer> maxQ = new LinkedList<>();while (++r < nums.length) {//当窗口还没遍历结束//如果队尾还有元素,且队尾元素比当前元素小while (!maxQ.isEmpty() && nums[maxQ.peekLast()] <= nums[r]) {maxQ.pollLast();}//到了这里说明队列为空或者队尾元素比当前元素大//当前元素入队尾maxQ.addLast(r);if (maxQ.peekFirst() == l) {//如果当前队头元素过期,出队maxQ.pollFirst();}if (r - l == k) {l++;res[index++] = nums[maxQ.peekFirst()];}}return res;}
}
2.每日温度
思路:维护一个由小到大的单调栈,栈顶元素最小。每次从栈顶加入一个数都要进行一次判断:
如果:加入的元素 <= 栈顶元素 满足单调性,直接入栈。
加入的元素 > 栈顶元素 栈顶元素弹出,一直弹到栈为空或者加入元素小于等于栈顶元素。
每次从栈顶弹出一次元素,对该元素进行计算。当前加入的元素,就是比栈顶弹出的元素大且离它最近的元素。
class Solution {public int[] dailyTemperatures(int[] temperatures) {//单调栈LinkedList<Integer> stack = new LinkedList<>();//用于保存结果,res[i] 就代表比temperatures[i] 大的右边最近一个元素距离i的位置int[] res = new int[temperatures.length];for (int i = 0; i < temperatures.length; i++) {//当栈为空,或者栈顶元素比当前元素大while (!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]) {Integer pop = stack.pop();res[pop] = i - pop;}//能到这一步说明,栈为空/栈顶元素大于等于当前元素stack.push(i);}return res;}
}
3.接雨水
思路:与上题略有不同的就是,本题还要找遍历当前值左侧最近且比当前值大的元素。就是栈中每个值下面一个元素。
class Solution {public int trap(int[] height) {int res = 0;LinkedList<Integer> stack = new LinkedList<>();for (int i = 0; i < height.length; i++) {while (!stack.isEmpty() && height[i] > height[stack.peek()]) {int pop = stack.pop();Integer peek = stack.peek();if (peek != null) {//peek == null 说明当前出栈的栈顶元素左边没有比它大的数// 出栈元素pop对应雨水面积的高为 左右两个中较小的那个 - pop元素的高 int h = Math.min(height[i], height[peek]) - height[pop];res += h * (i - peek - 1);}}stack.push(i);}return res;}
}
4.长度最小子序列(滑动窗口)
class Solution {public int minSubArrayLen(int target, int[] nums) {int res = Integer.MAX_VALUE;int l = 0;//代表滑动窗口左边界int r = 0;//代表滑动窗口右边界int cnt = 0;//用于计算窗口中元素的和while (r < nums.length) {while (r < nums.length) {//不断右移r往窗口中加元素cnt += nums[r];if (cnt >= target) break;r++;}while (l < r) {//不断缩小窗口if (cnt - nums[l] >= target) {cnt -= nums[l];l++;} else {break;}}//到了这一步,要不就是窗口中元素大于等于target,要不就是r遍历完res = Math.min(res, r - l + 1);r++;}return cnt >= target ? res : 0;}
}
相关文章:

算法刷题记录2
4.图 4.1.被围绕的区域 思路:图中只有与边界上联通的O才不算是被X包围。因此本题就是从边界上的O开始递归,找与边界O联通的O,并标记为#(代表已遍历),最后图中剩下的O就是:被X包围的O。图中所有…...

中国代工巨头旗下芯片公司遭网络攻击,千兆字节数据被泄露
近日,中国智能手机代工巨头闻泰科技旗下荷兰芯片制造商Nexperia发布声明,称其遭遇网络攻击,有未经授权的第三方访问了公司的 IT 服务器,目前已向相关部门报告了此次事件,并与网络安全专家合作开启调查。而据相关消息&a…...

【ARM 裸机】汇编 led 驱动之基本语法
我们要编写的是 ARM 汇编,编译使用的是 gcc 交叉编译器,所以要符合 GNU 语法。 1、汇编指令 汇编由一条条指令构成,ARM 不能直接访问存储器,比如 RAM 中的数据,I.MX6UL 中的寄存器就是 RAM 类型的,我们用…...

scala---基础核心知识(变量定义,数据类型,流程控制,方法定义,函数定义)
一、什么是scala Scala 是一种多范式的编程语言,其设计初衷是要集成面向对象编程和函数式编程的各种特性。Scala运行于Java平台(Java虚拟机),并兼容现有的Java程序。 二、为什么要学习scala 1、优雅 2、速度快 3、能融合到hado…...

OSPF星型拓扑和MGRE全连
一,拓扑 二,要求 1,R6为ISP只能配置IP地址,R1-R5的环回为私有网段 2,R1/4/5为全连的MGRE结构,R1/2/3为星型的拓扑结构, 3,R1为中心站点所有私有网段可以互相通讯,私有网段…...

智能时代中的工业应用中前所未有的灵活桥接和I/O扩展功能解决方案MachXO2系列LCMXO2-1200HC-4TG100I FPGA可编程逻辑IC
lattice莱迪斯 MachXO2系列LCMXO2-1200HC-4TG100I超低密度FPGA现场可编程门阵列,适用于低成本的复杂系统控制和视频接口设计开发,满足了通信、计算、工业、消费电子和医疗市场所需的系统控制和接口应用。 瞬时启动,迅速实现控制——启动时间…...

php:实现压缩文件上传、解压、文件更名、压缩包删除功能
效果图 1.上传文件 2.压缩包文件 3.itemno1文件 或 4.上传到系统路径\ItemNo 5.更名后的itemno1文件(命名:当天日期六位随机数) 代码 <form action"<?php echo htmlspecialchars($_SERVER[PHP_SELF], ENT_QUOTES, UTF-8); ?>" methodpost en…...

【机器学习】科学库使用第5篇:Matplotlib,学习目标【附代码文档】
机器学习(科学计算库)完整教程(附代码资料)主要内容讲述:机器学习(常用科学计算库的使用)基础定位、目标,机器学习概述定位,目标,学习目标,学习目标,1 人工智能应用场景,2 人工智能小…...

Java面试八股文(JVM篇)(❤❤)
Java面试八股文_JVM篇 1、知识点汇总2、知识点详解:3、说说类加载与卸载11、说说Java对象创建过程12、知道类的生命周期吗?14、如何判断对象可以被回收?17、调优命令有哪些?18、常见调优工具有哪些20、你知道哪些JVM性能调优参数&…...

「51媒体」如何有效进行媒体邀约,提升宣传传播效果?
传媒如春雨,润物细无声,大家好,我是51媒体网胡老师。 进行有效的媒体邀约,提升宣传传播效果的关键在于策略性和专业性。以下是具体的做法: 明确目标:要确立清晰的品牌推广目标和策略,包括确定目…...

docker初始化进程
docker run --init 是一个 Docker 命令的选项,用于在容器中运行一个初始化进程(通常是 tini)。这个初始化进程负责处理一些 Unix 信号(如 SIGTERM 和 SIGCHLD),并确保容器中的进程能够正确地被管理和清理。…...

基于快照行情的股票/基金 1分钟 K 线合成指南
1. 概述 由于不同交易所不同资产的交易规则是有差异的,导致不同交易所基于快照行情或逐笔成交合成不同资产1分钟 K 线的计算方法是不同的。 本教程旨在提高 DolphinDB 在具体业务场景下的落地效率,降低 DolphinDB 在实际业务使用中的开发难度。 本教程…...

新质生产力崛起:精益化能力助力企业转型升级
在智能制造、物联网、大数据、大模型、AI风起云涌的时代背景下,一个崭新的概念——“新质生产力”逐渐进入了人们的视野。这一热词不仅成为今年两会的讨论焦点,更代表了企业、国家乃至社会未来发展的核心动能。那么,什么是新质生产力…...

开发了一个在线客服系统
开发了一个在线客服系统 作为程序员,我一直在寻找能够提高工作效率和用户体验的方法。最近,我成功开发了一个在线客服系统,这个系统旨在帮助企业更高效地管理客户咨询和服务流程。 技术栈 我选择了以下的技术栈来构建这个系统:…...

cowa新的数据筛选代码
cowa新的数据筛选代码 代码地址: https://git.cowarobot.com/lhb/data_extracting 一阶段筛选 修改配置文件 config/common_stage.yamlversion: 3 services:de:image: harbor.cowarobot.cn/lhb/data:crpilot2.5-torch2.2environment:- CRPILOT_INSTALL_VERSIONx86…...

项目篇 | 图书管理系统 | 管理员模块 | 图书管理 | 删除
项目篇 | 图书管理系统 | 管理员模块 | 图书管理 | 删除 概述 图书管理页通过列表展示所有图书的相关信息,集成了搜索、添加、删除、修改的功能。 函数简介 // admin.h void delBook(); // 删除图书 void openDelBookMessage(); // 打开删除图书弹框 void closeDelBookMessa…...

自己动手封装axios通用方法并上传至私有npm仓库:详细步骤与实现指南
文章目录 一、构建方法1、api/request.js2、api/requestHandler.js3、api/index.js 二、测试方法1、api/axios.js2、main.js3、app.vue4、vue.config.js5、index.html 三、打包1、配置package.json2、生成库包3、配置发布信息4、发布 四、使用1、安装2、使用 五、维护1、维护和…...

【Sql Server】锁表如何解锁,模拟会话事务方式锁定一个表然后进行解锁
大家好,我是全栈小5,欢迎来到《小5讲堂》。 这是《Sql Server》系列文章,每篇文章将以博主理解的角度展开讲解。 温馨提示:博主能力有限,理解水平有限,若有不对之处望指正! 目录 前言创建表模拟…...

【大语言模型】轻松本地部署Stable Diffusion
硬件要求: 配备至少8GB VRAM的GPU,如果你的电脑只有CPU,请看到最后。根据部署规模,需要足够的CPU和RAM。 软件要求: Python 3.7或更高版本。支持NVIDIA GPU的PyTorch。Hugging Face的Diffusers库。Hugging Face的Tr…...

【github主页】优化简历
【github主页】优化简历 写在最前面一、新建秘密仓库二、插件卡片配置1、仓库状态统计2、Most used languages(GitHub 常用语言统计)使用细则 3、Visitor Badge(GitHub 访客徽章)4、社交统计5、打字特效6、省略展示小猫 …...

dnspy逆向和de4dot脱壳
拿到一个软件,使用dnspy查看,发现反汇编后关键部分的函数名和代码有很多乱码: 这样的函数非常多,要想进一步调试和逆向,就只能在dnspy中看反汇编代码了,而无法看到c#代码,当时的整个逆向过程只剩…...

python之flask安装以及使用
1 flask介绍 Flask是一个非常小的Python Web框架,被称为微型框架;只提供了一个稳健的核心,其他功能全部是通过扩展实现的;意思就是我们可以根据项目的需要量身定制,也意味着我们需要学习各种扩展库的使用。 2 python…...

汽车笔记-保险
保险 1.交强险 上路必须买的, 国家规定必须要买。交强险不管你是有责还是无责,它都是可以赔偿的。交强险还有一个18000的垫付功能,比如说我们出了交通事故后,对方住院治疗需要你垫付钱,那么这个时候就可以用到交强险…...

人工智能时代的图像识别:机遇与挑战并存
人工智能(AI)时代为图像识别领域带来了前所未有的机遇,同时也伴随着一系列挑战。这一领域的发展不仅深刻影响了科技、医疗、教育、娱乐等多个行业,还在一定程度上改变了人们的生活方式。 机遇: 技术突破与创新&#…...

工作 9 年后,回老家当计算机老师的真实感受
北京某程序员发帖,他说自己工作了整整 9 年后,今年六月就告别了北京这个大都市,安安心心地回老家当起了计算机老师。 工作日,每天早上 8 点就得按点上班儿,到了下午 4 点半,下班儿的铃声一响,就…...

二叉树的镜像【c++】
#include <iostream> #include <vector> using namespace std;//双链表节点结构 typedef struct treeNode {int value;struct treeNode* left;struct treeNode* right;treeNode(int x) : value(x), left(nullptr), right(nullptr) {} } TreeNode;void mirrorTree(T…...

记录Python的pandas库详解
如何生成一个pd import pandas as pd df pd.DataFrame([[1,2,3],[4,5,6]],index[A,B],columns[C1,C2,C3])df ---------------------------------------------------------------------------C1 C2 C3 A 1 2 3 B 4 5 6df.T -------------------------------------------------…...

阻碍团队使用工具的原因竟然是……
本文首发于个人网站「BY林子」,转载请参考版权声明。 工具化、自动化、数字化,这些都是逐步改善工作的质量和效率的方式,是时代不断进步的表现。然而,还是有很多软件开发团队的工作还处于手工阶段,这是为什么呢&#x…...

【并发】第九篇 Atomic原子操作类 - 字段更新器类详解
导航 简介AtomicIntegerFieldUpdater简介 Atomic的字段更新器类是Java中一种用于实现线程安全的字段更新操作的类。它提供了一组原子操作,可以对字段进行原子性的更新。在并发环境中,多个线程同时更新一个字段可能会出现竞态条件(Race Condition)导致数据不一致的问题。At…...

FFmpeg: 自实现ijkplayer播放器--03UI界面设计
文章目录 UI设计流程图UI设计界面点击播放功能实现 UI设计流程图 UI设计界面 主界面 控制条 播放列表 画面显示 标题栏 设置界面 提示框 点击播放功能实现 槽函数实现: connect(ui->ctrlBarWind, &CtrlBar::SigPlayOrPause, this, &Main…...