算法刷题记录2
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、省略展示小猫 …...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...


