This commit is contained in:
zhangsan 2025-09-27 12:25:49 +08:00
parent 80302c704a
commit 8d4440e0dc
25 changed files with 599 additions and 12 deletions

View File

@ -0,0 +1,55 @@
package All;
import java.util.*;
/**
* 题目 735. 小行星碰撞
* 描述给定一个整数数组 asteroids表示在同一行的小行星数组中小行星的索引表示它们在空间中的相对位置
* 对于数组中的每一个元素其绝对值表示小行星的大小正负表示小行星的移动方向正表示向右移动负表示向左移动每一颗小行星以相同的速度移动
* 找出碰撞后剩下的所有小行星碰撞规则两个小行星相互碰撞较小的小行星会爆炸如果两颗小行星大小相同则两颗小行星都会爆炸两颗移动方向相同的小行星永远不会发生碰撞
示例 1
输入
输入asteroids = [5,10,-5]
输出[5,10]
解释10 -5 碰撞后只剩下 10 5 10 永远不会发生碰撞
* 链接https://leetcode.cn/problems/asteroid-collision/
*/
public class AsteroidCollision {
public int[] asteroidCollision(int[] asteroids) {
Deque<Integer> stack=new ArrayDeque<>();
List<Integer>res=new ArrayList<>();
for (int i = 0; i < asteroids.length; i++) {
if(stack.isEmpty()){
stack.push(asteroids[i]);
}else {
int cur=asteroids[i];
if(cur>0)stack.push(cur);
else {
boolean flag=true;
while (!stack.isEmpty()&&stack.peek()>0){
int curr=Math.abs(cur);
if(stack.peek()>curr){
flag=false;
break;
} else if (stack.peek()==curr) {
flag=false;
stack.pop();
break;
}else
stack.pop();
}
if(flag)stack.push(cur);
}
}
}
while (!stack.isEmpty())
res.add(0,stack.pop());
int[] arr = new int[res.size()];
for (int i = 0; i < res.size(); i++) {
arr[i] = res.get(i);
}
return arr;
}
}

View File

@ -0,0 +1,49 @@
package All;
/**
* 题目 1254. 统计封闭岛屿的数目
* 描述二维矩阵 grid 0 土地 1 组成岛是由最大的4个方向连通的 0 组成的群封闭岛是一个 完全 由1包围的岛
* 请返回 封闭岛屿 的数目
示例 1
输入grid = [[1,1,1,1,1,1,1,0],[1,0,0,0,0,1,1,0],[1,0,1,0,1,1,1,0],[1,0,0,0,0,1,0,1],[1,1,1,1,1,1,1,0]]
输出2
解释
灰色区域的岛屿是封闭岛屿因为这座岛屿完全被水域包围即被 1 区域包围
* 链接https://leetcode.cn/problems/number-of-closed-islands/
*/
public class ClosedIsland {
int[][]dirs=new int[][]{{-1,0},{0,1},{1,0},{0,-1}};
boolean dfs(int[][] grid,int i,int j){
int row=grid.length,col=grid[0].length;
if(i<0 || i>=row || j<0 || j>=col)return false;
int cur=grid[i][j];
if(cur==0){
grid[i][j]=2;
boolean isClosed = true;
for (int k = 0; k < 4; k++) {
if (!dfs(grid, i + dirs[k][0], j + dirs[k][1])) {
isClosed = false;
}
}
return isClosed;
}
return true;
}
public int closedIsland(int[][] grid) {
int cnt=0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if(grid[i][j]==0)
if(dfs(grid,i,j))
cnt++;
}
}
return cnt;
}
public static void main(String[] args) {
}
}

View File

@ -0,0 +1,38 @@
package All;
/**
* 题目 3101. 交替子数组计数
* 描述给你一个二进制数组nums
* 如果一个子数组中 不存在 两个 相邻 元素的值 相同 的情况我们称这样的子数组为 交替子数组
* 返回数组 nums 中交替子数组的数量
示例 1
输入 nums = [0,1,1,1]
输出 5
解释
以下子数组是交替子数组[0] [1] [1] [1] 以及 [0,1]
* 链接https://leetcode.cn/problems/count-alternating-subarrays/
*/
public class CountAlternatingSubarrays {
public long countAlternatingSubarrays(int[] nums) {
int prenum=nums[0],precnt=1;
long total=1;
for (int i = 1; i < nums.length; i++) {
if(prenum==nums[i]){
precnt=1;
}else {
precnt++;
}
prenum=nums[i];
total += precnt;
}
return total;
}
public static void main(String[] args) {
CountAlternatingSubarrays countAlternatingSubarrays = new CountAlternatingSubarrays();
int[] nums = new int[]{0,1,1,1};
long total=countAlternatingSubarrays.countAlternatingSubarrays(nums);
System.out.println(total);
}
}

View File

@ -0,0 +1,65 @@
package All;
import java.util.Deque;
import java.util.LinkedList;
/**
* 题目 1696. 跳跃游戏 VI
* 描述给你一个下标从 0 开始的整数数组 nums 和一个整数 k
* 一开始你在下标 0 每一步你最多可以往前跳 k 但你不能跳出数组的边界也就是说你可以从下标 i 跳到 [i + 1 min(n - 1, i + k)] 包含 两个端点的任意位置
* 你的目标是到达数组最后一个位置下标为 n - 1 你的 得分 为经过的所有数字之和
* 请你返回你能得到的 最大得分
示例 1
输入nums = [1,-1,-2,4,-7,3], k = 2
输出7
解释你可以选择子序列 [1,-1,4,3] 上面加粗的数字和为 7
* 链接https://leetcode.cn/problems/jump-game-vi/
*/
//不会做
public class MaxResult {
//超时
public int maxResult2(int[] nums, int k) {
int n = nums.length;
int[] f = new int[n];
f[0] = nums[0];
for (int i = 1; i < n; i++) {
int mx = Integer.MIN_VALUE;
for (int j = Math.max(i - k, 0); j < i; j++) {
mx = Math.max(mx, f[j]);
}
f[i] = mx + nums[i];
}
return f[n - 1];
}
/*
dp[i] = max(dp[j]) + nums[i]其中 j [i - k, i - 1]
用一个双端队列存放候选下标保持队列里的 dp 值是单调递减的这样队首永远是最大值
*/
public int maxResult(int[] nums, int k) {
int n = nums.length;
int[] dp = new int[n];
dp[0] = nums[0];
Deque<Integer> deque = new LinkedList<>();
deque.offer(0); // 队列存的是下标
for (int i = 1; i < n; i++) {
// 队首如果滑出窗口 [i-k, i-1] 就移除
while (!deque.isEmpty() && deque.peek() < i - k) {
deque.poll();
}
// 队首就是窗口内 dp 最大值的下标
dp[i] = dp[deque.peek()] + nums[i];
// 保持队列单调递减把比当前 dp[i] 小的值都踢掉
while (!deque.isEmpty() && dp[i] >= dp[deque.peekLast()]) {
deque.pollLast();
}
deque.offer(i);
}
return dp[n - 1];
}
}

View File

@ -0,0 +1,21 @@
package All;
/**
* 题目 1227. 飞机座位分配概率
* 描述 n 位乘客即将登机飞机正好有 n 个座位第一位乘客的票丢了他随便选了一个座位坐下
* 剩下的乘客将会
* 如果他们自己的座位还空着就坐到自己的座位上
* 当他们自己的座位被占用时随机选择其他座位
* n 位乘客坐在自己的座位上的概率是多少
示例 1
输入: n = 2
输出: 0.50000
解释在第一个人选好座位坐下后第二个人坐在自己的座位上的概率是 0.5
* 链接https://leetcode.cn/problems/airplane-seat-assignment-probability/
*/
public class NthPersonGetsNthSeat {
public double nthPersonGetsNthSeat(int n) {
return n == 1? 1: 0.5;
}
}

View File

@ -0,0 +1,39 @@
package All;
/**
* 题目 3208. 交替组 II
* 描述给你一个整数数组 colors 和一个整数 k colors表示一个由红色和蓝色瓷砖组成的环 i 块瓷砖的颜色为 colors[i]
* colors[i] == 0 表示第 i 块瓷砖的颜色是 红色
* colors[i] == 1 表示第 i 块瓷砖的颜色是 蓝色
* 环中连续 k 块瓷砖的颜色如果是 交替 颜色也就是说除了第一块和最后一块瓷砖以外中间瓷砖的颜色与它 左边 右边 的颜色都不同那么它被称为一个 交替
* 请你返回 交替 组的数目
* 注意 由于 colors 表示一个 第一块 瓷砖和 最后一块 瓷砖是相邻的
示例 1
输入colors = [0,1,0,1,0], k = 3
输出3
* 链接https://leetcode.cn/problems/alternating-groups-ii/
*/
//不会
public class NumberOfAlternatingGroupsa {
public int numberOfAlternatingGroups(int[] colors, int k) {
int n = colors.length;
int ans = 0;
int cnt = 0; // 当前连续交替子段的长度
for (int i = 0; i < n + k - 1; i++) {
// 更新 cnt
if (colors[i % n] == colors[(i + 1) % n]) {
cnt = 0;
}
cnt++;
if (cnt >= k) ans++;
}
return ans;
}
public static void main(String[] args) {
NumberOfAlternatingGroupsa solution = new NumberOfAlternatingGroupsa();
System.out.println(solution.numberOfAlternatingGroups(new int[]{0,1,0,1,0}, 3)); // 3
}
}

View File

@ -0,0 +1,72 @@
package All;
import java.util.*;
/**
* 题目 1366. 通过投票对团队排名
* 描述现在有一个特殊的排名系统依据参赛团队在投票人心中的次序进行排名每个投票者都需要按从高到低的顺序对参与排名的所有团队进行排位
* 排名规则如下
* 参赛团队的排名次序依照其所获排位第一的票的多少决定如果存在多个团队并列的情况将继续考虑其排位第二的票的数量以此类推直到不再存在并列的情况
* 如果在考虑完所有投票情况后仍然出现并列现象则根据团队字母的字母顺序进行排名
* 给你一个字符串数组 votes 代表全体投票者给出的排位情况请你根据上述排名规则对所有参赛团队进行排名
* 请你返回能表示按排名系统 排序后 的所有团队排名的字符串
示例 1
输入votes = ["ABC","ACB","ABC","ACB","ACB"]
输出"ACB"
解释
A 队获得五票排位第一没有其他队获得排位第一所以 A 队排名第一
B 队获得两票排位第二三票排位第三
C 队获得三票排位第二两票排位第三
由于 C 排位第二的票数较多所以 C 队排第二B 队排第三
* 链接https://leetcode.cn/problems/rank-teams-by-votes/
*/
//不会
public class RankTeams {
public String rankTeams(String[] votes) {
int n = votes[0].length(); // 队伍总数每张票都包含全部队伍
// map 统计每个队伍在每个名次上的票数
Map<Character, int[]> countMap = new HashMap<>();
for (String vote : votes) {
for (int i = 0; i < n; i++) {
char team = vote.charAt(i);
if (!countMap.containsKey(team)) {
countMap.put(team, new int[n]);
}
countMap.get(team)[i]++; // team 在第 i 个名次上多一票
}
}
// 所有参赛队伍
List<Character> teams = new ArrayList<>(countMap.keySet());
// 自定义排序规则
// 1. 优先比较每个名次的票数从第一名到最后一名
// 2. 如果所有名次票数相同则按字母顺序排
Collections.sort(teams, (a, b) -> {
int[] cntA = countMap.get(a);
int[] cntB = countMap.get(b);
for (int i = 0; i < n; i++) {
if (cntA[i] != cntB[i]) {
return cntB[i] - cntA[i]; // 谁在这一名上的票多谁排前面
}
}
return a - b; // 所有票数相同按字母顺序
});
// 拼接成最终结果
StringBuilder sb = new StringBuilder();
for (char team : teams) {
sb.append(team);
}
return sb.toString();
}
public static void main(String[] args) {
RankTeams solution = new RankTeams();
String[] votes = {"ABC","ACB","ABC","ACB","ACB"};
System.out.println(solution.rankTeams(votes)); // 输出 "ACB"
}
}

View File

@ -0,0 +1,28 @@
package All;
/**
* 题目 796. 旋转字符串
* 描述给定两个字符串, s goal如果在若干次旋转操作之后s 能变成 goal 那么返回 true
* s 旋转操作 就是将 s 最左边的字符移动到最右边
* 例如, s = 'abcde'在旋转一次之后结果就是'bcdea'
示例 1
输入: s = "abcde", goal = "cdeab"
输出: true
* 链接https://leetcode.cn/problems/rotate-string/
*/
public class RotateString {
public boolean rotateString(String s, String goal) {
int target=goal.length();
int len=s.length();
if(target!=len)return false;
for (int i = 0; i < len; i++) {
for (int j = 0; j < target; j++) {
if(s.charAt((i+j)%len)!=goal.charAt(j))
break;
if(j==target-1)return true;
}
}
return false;
}
}

View File

@ -0,0 +1,43 @@
package All;
/**
* 题目 640. 求解方程
* 描述求解一个给定的方程将x以字符串 "x=#value" 的形式返回该方程仅包含 '+' '-' 操作变量 x 和其对应系数
*
* 如果方程没有解或存在的解不为整数请返回 "No solution" 如果方程有无限解则返回 Infinite solutions
*
* 题目保证如果方程中只有一个解 'x' 的值是一个整数
示例 1
输入: equation = "x+5-3+x=6+x-2"
输出: "x=2"
* 链接https://leetcode.cn/problems/solve-the-equation/
*/
public class SolveEquation {
class Solution {
public String solveEquation(String s) {
int x = 0, num = 0, n = s.length();
char[] cs = s.toCharArray();
for (int i = 0, op = 1; i < n; ) {
if (cs[i] == '+') {
op = 1; i++;
} else if (cs[i] == '-') {
op = -1; i++;
} else if (cs[i] == '=') {
x *= -1; num *= -1; op = 1; i++;
} else {
int j = i;
//找当前数字/变量的边界 比如 "3x""x""5"
while (j < n && cs[j] != '+' && cs[j] != '-' && cs[j] != '=') j++;
//"3x" "3" "x" 前面没数字这时就走 else 1表示系数是 1
if (cs[j - 1] == 'x') x += (i < j - 1 ? Integer.parseInt(s.substring(i, j - 1)) : 1) * op;
//如果不是 x 就说明是数字比如 "5""10"
else num += Integer.parseInt(s.substring(i, j)) * op;
i = j;
}
}
if (x == 0) return num == 0 ? "Infinite solutions" : "No solution";
else return "x=" + (num / -x);
}
}
}

View File

@ -0,0 +1,40 @@
package All;
/**
* 题目 680. 验证回文串 II
* 描述给你一个字符串 s最多 可以从中删除一个字符
* 请你判断 s 是否能成为回文字符串如果能返回 true 否则返回 false
示例 1
输入s = "aba"
输出true
* 链接https://leetcode.cn/problems/valid-palindrome-ii/
*/
public class ValidPalindrome {
public boolean validPalindrome(String s) {
int l = 0, r = s.length() - 1;
while (l < r) {
if (s.charAt(l) == s.charAt(r)) {
l++; r--;
} else {
// 尝试跳过左边或右边的字符
return isPalindrome(s, l + 1, r) || isPalindrome(s, l, r - 1);
}
}
return true;
}
private boolean isPalindrome(String s, int l, int r) {
while (l < r) {
if (s.charAt(l++) != s.charAt(r--)) return false;
}
return true;
}
public static void main(String[] args) {
ValidPalindrome solution = new ValidPalindrome();
String s="bddb";
solution.validPalindrome(s);
}
}

View File

@ -0,0 +1,47 @@
package All;
import java.util.HashMap;
import java.util.Map;
/*
* 题目 680. 验证回文串 II
* 描述给你一个字符串 s最多 可以从中删除 k 个字符
* 请你判断 s 是否能成为回文字符串如果能返回 true 否则返回 false
*/
public class ValidPalindromeK {
public boolean validPalindrome(String s, int k) {
// 从整个字符串 [0..n-1] 开始判断初始可删 k
return judge(s, 0, s.length() - 1, k, new HashMap<>());
}
private boolean judge(String s, int l, int r, int k, Map<String, Boolean> memo) {
// "l,r,k" 作为 key 唯一标识当前子问题
String key = l + "," + r + "," + k;
if (memo.containsKey(key)) return memo.get(key);
while (l < r) {
if (s.charAt(l) == s.charAt(r)) {
l++; r--;
} else {
if (k == 0) {
memo.put(key, false);
return false;
}
// 尝试两种删除方式
// 1. 删除左边字符l+1, r, k-1
// 2. 删除右边字符l, r-1, k-1
boolean res = judge(s, l + 1, r, k - 1, memo) || judge(s, l, r - 1, k - 1, memo);
memo.put(key, res);
return res;
}
}
memo.put(key, true);
return true;
}
public static void main(String[] args) {
ValidPalindromeK solution = new ValidPalindromeK();
System.out.println(solution.validPalindrome("bddb", 1)); // true
System.out.println(solution.validPalindrome("abc", 1)); // false
System.out.println(solution.validPalindrome("abc", 2)); // true (删掉 "a" "c")
}
}

View File

@ -13,6 +13,7 @@ package dynamic_programming;
* 链接https://leetcode.cn/problems/palindromic-substrings/
*/
//不会
//二刷不会
public class CountSubstrings {
/**
*布尔类型的dp[i][j]表示区间范围[i,j] 注意是左闭右闭的子串是否是回文子串

View File

@ -24,6 +24,7 @@ package dynamic_programming;
* dp[i][j] = 0;
*/
//二刷不会
//三刷会做
public class FindLength {
public int findLength(int[] nums1, int[] nums2) {
int n = nums1.length, m = nums2.length;

View File

@ -19,6 +19,7 @@ package dynamic_programming;
* 链接https://leetcode.cn/problems/target-sum/
*/
//二刷不会
//三刷不会,数学转换很重要
public class FindTargetSumWays {
/**

View File

@ -12,6 +12,7 @@ package dynamic_programming;
* 链接https://leetcode.cn/problems/longest-palindromic-substring/
*/
//二刷不会
//三刷会做
public class LongestPalindrome {
/*
遍历顺序为什么是 i 从大到小j 从小到大

View File

@ -11,6 +11,7 @@ package dynamic_programming;
* 链接https://leetcode.cn/problems/longest-palindromic-subsequence/
*/
//二刷会做
public class LongestPalindromeSubseq {
public int longestPalindromeSubseq(String s) {
int n = s.length();

View File

@ -13,6 +13,7 @@ package dynamic_programming;
*/
//不会
//二刷不会
//三刷不会
public class MaxProduct {
/**

View File

@ -11,6 +11,7 @@ package dynamic_programming;
* 链接https://leetcode.cn/problems/maximum-subarray/
*/
//会做
public class MaxSubArray {
//dp[i]包括下标i以nums[i]为结尾的最大连续子序列和为dp[i]
public static int maxSubArray(int[] nums) {

View File

@ -10,22 +10,19 @@ package dynamic_programming;
* 链接https://leetcode.cn/problems/maximal-square/
*/
//不会
//二刷不会
public class MaximalSquare {
/**
* dp[i][j] 表示 (i, j) 作为右下角的最大全 1 正方形的边长
*
* 那么如何计算 dp 中的每个元素值呢对于每个位置 (i,j)检查在矩阵中该位置的值
*
* 如果该位置的值是 0 dp(i,j)=0因为当前位置不可能在由 1 组成的正方形中
*
* 如果该位置的值是 1 dp(i,j) 的值由其上方左方和左上方的三个相邻位置的 dp 值决定具体而言当前位置的元素值等于三个相邻位置的元素中的最小值加 1状态转移方程如下
*
* dp(i,j)=min(dp(i1,j),dp(i1,j1),dp(i,j1))+1
*
* 作者力扣官方题解
* 链接https://leetcode.cn/problems/maximal-square/solutions/234964/zui-da-zheng-fang-xing-by-leetcode-solution/
* 来源力扣LeetCode
* 著作权归作者所有商业转载请联系作者获得授权非商业转载请注明出处
* @param matrix
* @return
*/
public int maximalSquare(char[][] matrix) {
int maxSide = 0;

View File

@ -14,11 +14,13 @@ package dynamic_programming;
* 链接https://leetcode.cn/problems/min-cost-climbing-stairs/
*/
//会做
public class MinCostClimbingStairs {
//dp[i] 表示到达第 i 个台阶所需要支付的最小花费
public int minCostClimbingStairs(int[] cost) {
int n = cost.length;
int[] dp = new int[n + 1];
// 默认第一步和第二步不花费体力
// 默认第一步和第二步不花费
dp[0] = 0;
dp[1] = 0;
// 从第 2 阶开始递推计算到顶楼

View File

@ -42,7 +42,6 @@ public class NumIslands {
}
}
}
return num_islands;
}
}

View File

@ -48,4 +48,20 @@ public class Jump {
}
return count;
}
public int jump2(int[] nums) {
if(nums.length==1)return 0;
int curmax=0,allmax=nums[0];
int step=0;
for (int i = 0; i < nums.length; i++) {
allmax=Math.max(allmax,i+nums[i]);
if(allmax>=nums.length-1)return step+1;
if(i==curmax){
step++;
curmax=allmax;
}
}
return -1;
}
}

View File

@ -0,0 +1,55 @@
package stack;
import java.util.*;
/**
* 题目 735. 小行星碰撞
* 描述给定一个整数数组 asteroids表示在同一行的小行星数组中小行星的索引表示它们在空间中的相对位置
* 对于数组中的每一个元素其绝对值表示小行星的大小正负表示小行星的移动方向正表示向右移动负表示向左移动每一颗小行星以相同的速度移动
* 找出碰撞后剩下的所有小行星碰撞规则两个小行星相互碰撞较小的小行星会爆炸如果两颗小行星大小相同则两颗小行星都会爆炸两颗移动方向相同的小行星永远不会发生碰撞
示例 1
输入
输入asteroids = [5,10,-5]
输出[5,10]
解释10 -5 碰撞后只剩下 10 5 10 永远不会发生碰撞
* 链接https://leetcode.cn/problems/asteroid-collision/
*/
public class AsteroidCollision {
public int[] asteroidCollision(int[] asteroids) {
Deque<Integer> stack=new ArrayDeque<>();
List<Integer>res=new ArrayList<>();
for (int i = 0; i < asteroids.length; i++) {
if(stack.isEmpty()){
stack.push(asteroids[i]);
}else {
int cur=asteroids[i];
if(cur>0)stack.push(cur);
else {
boolean flag=true;
while (!stack.isEmpty()&&stack.peek()>0){
int curr=Math.abs(cur);
if(stack.peek()>curr){
flag=false;
break;
} else if (stack.peek()==curr) {
flag=false;
stack.pop();
break;
}else
stack.pop();
}
if(flag)stack.push(cur);
}
}
}
while (!stack.isEmpty())
res.add(0,stack.pop());
int[] arr = new int[res.size()];
for (int i = 0; i < res.size(); i++) {
arr[i] = res.get(i);
}
return arr;
}
}

View File

@ -1,5 +1,6 @@
package 实现类功能;
/*
实现一个HashMap
数组table核心结构存储键值对Entry的桶bucket
链表当多个键的哈希值落在同一个桶中时会形成一个链表
*/

View File

@ -0,0 +1,13 @@
package All;
import junit.framework.TestCase;
public class MaxResultTest extends TestCase {
public void testMaxResult() {
MaxResult maxResult=new MaxResult();
int[]nums = {10,-5,-2,4,0,3};
int res=maxResult.maxResult(nums,3);
System.out.println(res);
}
}