Skip to content

Commit

Permalink
Merge branch 'master' of github.com:youngyangyang04/leetcode-master
Browse files Browse the repository at this point in the history
youngyangyang04 committed Apr 12, 2024

Verified

This commit was signed with the committer’s verified signature.
raydouglass Ray Douglass
2 parents f835589 + f5fcd62 commit a6ba82a
Showing 13 changed files with 242 additions and 37 deletions.
1 change: 0 additions & 1 deletion .gitignore

This file was deleted.

42 changes: 24 additions & 18 deletions problems/0019.删除链表的倒数第N个节点.md
Original file line number Diff line number Diff line change
@@ -98,27 +98,33 @@ public:
### Java:
```java
public ListNode removeNthFromEnd(ListNode head, int n){
ListNode dummyNode = new ListNode(0);
dummyNode.next = head;
ListNode fastIndex = dummyNode;
ListNode slowIndex = dummyNode;
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
//新建一个虚拟头节点指向head
ListNode dummyNode = new ListNode(0);
dummyNode.next = head;
//快慢指针指向虚拟头节点
ListNode fastIndex = dummyNode;
ListNode slowIndex = dummyNode;
// 只要快慢指针相差 n 个结点即可
for (int i = 0; i <= n; i++) {
fastIndex = fastIndex.next;
}
// 只要快慢指针相差 n 个结点即可
for (int i = 0; i < n ; i++){
fastIndex = fastIndex.next;
}
while (fastIndex != null) {
fastIndex = fastIndex.next;
slowIndex = slowIndex.next;
}
while (fastIndex != null){
fastIndex = fastIndex.next;
slowIndex = slowIndex.next;
// 此时 slowIndex 的位置就是待删除元素的前一个位置。
// 具体情况可自己画一个链表长度为 3 的图来模拟代码来理解
// 检查 slowIndex.next 是否为 null,以避免空指针异常
if (slowIndex.next != null) {
slowIndex.next = slowIndex.next.next;
}
return dummyNode.next;
}
//此时 slowIndex 的位置就是待删除元素的前一个位置。
//具体情况可自己画一个链表长度为 3 的图来模拟代码来理解
slowIndex.next = slowIndex.next.next;
return dummyNode.next;
}
```

19 changes: 18 additions & 1 deletion problems/0027.移除元素.md
Original file line number Diff line number Diff line change
@@ -247,6 +247,24 @@ class Solution:

### Go:

```go
// 暴力法
// 时间复杂度 O(n^2)
// 空间复杂度 O(1)
func removeElement(nums []int, val int) int {
size := len(nums)
for i := 0; i < size; i ++ {
if nums[i] == val {
for j := i + 1; j < size; j ++ {
nums[j - 1] = nums[j]
}
i --
size --
}
}
return size
}
```
```go
// 快慢指针法
// 时间复杂度 O(n)
@@ -289,7 +307,6 @@ func removeElement(nums []int, val int) int {
right--
}
}
fmt.Println(nums)
return left
}
```
Original file line number Diff line number Diff line change
@@ -233,7 +233,7 @@ class Solution {
if (index == -1) { // nums 中不存在 target,直接返回 {-1, -1}
return new int[] {-1, -1}; // 匿名数组
}
// nums 中存在 targe,则左右滑动指针,来找到符合题意的区间
// nums 中存在 target,则左右滑动指针,来找到符合题意的区间
int left = index;
int right = index;
// 向左滑动,找左边界
@@ -450,7 +450,7 @@ class Solution:
return -1
index = binarySearch(nums, target)
if index == -1:return [-1, -1] # nums 中不存在 target,直接返回 {-1, -1}
# nums 中存在 targe,则左右滑动指针,来找到符合题意的区间
# nums 中存在 target,则左右滑动指针,来找到符合题意的区间
left, right = index, index
# 向左滑动,找左边界
while left -1 >=0 and nums[left - 1] == target: left -=1
27 changes: 27 additions & 0 deletions problems/0042.接雨水.md
Original file line number Diff line number Diff line change
@@ -440,6 +440,33 @@ class Solution {
}
```

双指针优化
```java
class Solution {
public int trap(int[] height) {
if (height.length <= 2) {
return 0;
}
// 从两边向中间寻找最值
int maxLeft = height[0], maxRight = height[height.length - 1];
int l = 1, r = height.length - 2;
int res = 0;
while (l <= r) {
// 不确定上一轮是左边移动还是右边移动,所以两边都需更新最值
maxLeft = Math.max(maxLeft, height[l]);
maxRight = Math.max(maxRight, height[r]);
// 最值较小的一边所能装的水量已定,所以移动较小的一边。
if (maxLeft < maxRight) {
res += maxLeft - height[l ++];
} else {
res += maxRight - height[r --];
}
}
return res;
}
}
```

单调栈法

```java
18 changes: 18 additions & 0 deletions problems/0062.不同路径.md
Original file line number Diff line number Diff line change
@@ -285,6 +285,24 @@ public:
}
```
状态压缩
```java
class Solution {
public int uniquePaths(int m, int n) {
// 在二维dp数组中,当前值的计算只依赖正上方和正左方,因此可以压缩成一维数组。
int[] dp = new int[n];
// 初始化,第一行只能从正左方跳过来,所以只有一条路径。
Arrays.fill(dp, 1);
for (int i = 1; i < m; i ++) {
// 第一列也只有一条路,不用迭代,所以从第二列开始
for (int j = 1; j < n; j ++) {
dp[j] += dp[j - 1]; // dp[j] = dp[j] (正上方)+ dp[j - 1] (正左方)
}
}
return dp[n - 1];
}
}
```

### Python
递归
3 changes: 0 additions & 3 deletions problems/0121.买卖股票的最佳时机.md
Original file line number Diff line number Diff line change
@@ -287,9 +287,6 @@ class Solution {
return dp[1];
}
}
```
```Java
```
### Python:
2 changes: 1 addition & 1 deletion problems/0343.整数拆分.md
Original file line number Diff line number Diff line change
@@ -296,7 +296,7 @@ class Solution:
def integerBreak(self, n):
if n == 2: # 当n等于2时,只有一种拆分方式:1+1=2,乘积为1
return 1
if n == 3: # 当n等于3时,只有一种拆分方式:1+1+1=3,乘积为1
if n == 3: # 当n等于3时,只有一种拆分方式:2+1=3,乘积为2
return 2
if n == 4: # 当n等于4时,有两种拆分方式:2+2=4和1+1+1+1=4,乘积都为4
return 4
27 changes: 26 additions & 1 deletion problems/0347.前K个高频元素.md
Original file line number Diff line number Diff line change
@@ -218,7 +218,7 @@ class Solution {
```

### Python:

解法一:
```python
#时间复杂度:O(nlogk)
#空间复杂度:O(n)
@@ -246,6 +246,31 @@ class Solution:
result[i] = heapq.heappop(pri_que)[1]
return result
```
解法二:
```python
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
# 使用字典统计数字出现次数
time_dict = defaultdict(int)
for num in nums:
time_dict[num] += 1
# 更改字典,key为出现次数,value为相应的数字的集合
index_dict = defaultdict(list)
for key in time_dict:
index_dict[time_dict[key]].append(key)
# 排序
key = list(index_dict.keys())
key.sort()
result = []
cnt = 0
# 获取前k项
while key and cnt != k:
result += index_dict[key[-1]]
cnt += len(index_dict[key[-1]])
key.pop()

return result[0: k]
```

### Go:

57 changes: 57 additions & 0 deletions problems/0392.判断子序列.md
Original file line number Diff line number Diff line change
@@ -173,6 +173,63 @@ class Solution {
}
}
```
> 修改遍历顺序后,可以利用滚动数组,对dp数组进行压缩
```java
class Solution {
public boolean isSubsequence(String s, String t) {
// 修改遍历顺序,外圈遍历t,内圈遍历s。使得dp的推算只依赖正上方和左上方,方便压缩。
int[][] dp = new int[t.length() + 1][s.length() + 1];
for (int i = 1; i < dp.length; i++) { // 遍历t字符串
for (int j = 1; j < dp[i].length; j++) { // 遍历s字符串
if (t.charAt(i - 1) == s.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = dp[i - 1][j];
}
}
System.out.println(Arrays.toString(dp[i]));
}
return dp[t.length()][s.length()] == s.length();
}
}
```
> 状态压缩
```java
class Solution {
public boolean isSubsequence(String s, String t) {
int[] dp = new int[s.length() + 1];
for (int i = 0; i < t.length(); i ++) {
// 需要使用上一轮的dp[j - 1],所以使用倒序遍历
for (int j = dp.length - 1; j > 0; j --) {
// i遍历的是t字符串,j遍历的是dp数组,dp数组的长度比s的大1,因此需要减1。
if (t.charAt(i) == s.charAt(j - 1)) {
dp[j] = dp[j - 1] + 1;
}
}
}
return dp[s.length()] == s.length();
}
}
```
> 将dp定义为boolean类型,dp[i]直接表示s.substring(0, i)是否为t的子序列
```java
class Solution {
public boolean isSubsequence(String s, String t) {
boolean[] dp = new boolean[s.length() + 1];
// 表示 “” 是t的子序列
dp[0] = true;
for (int i = 0; i < t.length(); i ++) {
for (int j = dp.length - 1; j > 0; j --) {
if (t.charAt(i) == s.charAt(j - 1)) {
dp[j] = dp[j - 1];
}
}
}
return dp[dp.length - 1];
}
}
```

### Python:

18 changes: 17 additions & 1 deletion problems/0674.最长连续递增序列.md
Original file line number Diff line number Diff line change
@@ -186,7 +186,23 @@ public:
return res;
}
```
> 动态规划状态压缩
```java
class Solution {
public int findLengthOfLCIS(int[] nums) {
// 记录以 前一个元素结尾的最长连续递增序列的长度 和 以当前 结尾的......
int beforeOneMaxLen = 1, currentMaxLen = 0;
// res 赋最小值返回的最小值1
int res = 1;
for (int i = 1; i < nums.length; i ++) {
currentMaxLen = nums[i] > nums[i - 1] ? beforeOneMaxLen + 1 : 1;
beforeOneMaxLen = currentMaxLen;
res = Math.max(res, currentMaxLen);
}
return res;
}
}
```
> 贪心法:
```Java
18 changes: 18 additions & 0 deletions problems/0746.使用最小花费爬楼梯.md
Original file line number Diff line number Diff line change
@@ -244,6 +244,24 @@ class Solution {
}
```

```Java
// 状态压缩,使用三个变量来代替数组
class Solution {
public int minCostClimbingStairs(int[] cost) {
// 以下三个变量分别表示前两个台阶的最少费用、前一个的、当前的。
int beforeTwoCost = 0, beforeOneCost = 0, currentCost = 0;
// 前两个台阶不需要费用就能上到,因此从下标2开始;因为最后一个台阶需要跨越,所以需要遍历到cost.length
for (int i = 2; i <= cost.length; i ++) {
// 此处遍历的是cost[i - 1],不会越界
currentCost = Math.min(beforeOneCost + cost[i - 1], beforeTwoCost + cost[i - 2]);
beforeTwoCost = beforeOneCost;
beforeOneCost = currentCost;
}
return currentCost;
}
}
```

### Python

动态规划(版本一)
43 changes: 34 additions & 9 deletions problems/kama0054.替换数字.md
Original file line number Diff line number Diff line change
@@ -146,17 +146,42 @@ for (int i = 0; i < a.size(); i++) {
```java
import java.util.Scanner;

class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String s = in.nextLine();
StringBuilder sb = new StringBuilder();
public class Main {

public static String replaceNumber(String s) {
int count = 0; // 统计数字的个数
int sOldSize = s.length();
for (int i = 0; i < s.length(); i++) {
if (Character.isDigit(s.charAt(i))) {
sb.append("number");
}else sb.append(s.charAt(i));
if(Character.isDigit(s.charAt(i))){
count++;
}
}
System.out.println(sb);
// 扩充字符串s的大小,也就是每个空格替换成"number"之后的大小
char[] newS = new char[s.length() + count * 5];
int sNewSize = newS.length;
// 将旧字符串的内容填入新数组
System.arraycopy(s.toCharArray(), 0, newS, 0, sOldSize);
// 从后先前将空格替换为"number"
for (int i = sNewSize - 1, j = sOldSize - 1; j < i; j--, i--) {
if (!Character.isDigit(newS[j])) {
newS[i] = newS[j];
} else {
newS[i] = 'r';
newS[i - 1] = 'e';
newS[i - 2] = 'b';
newS[i - 3] = 'm';
newS[i - 4] = 'u';
newS[i - 5] = 'n';
i -= 5;
}
}
return new String(newS);
};
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String s = scanner.next();
System.out.println(replaceNumber(s));
scanner.close();
}
}
```

0 comments on commit a6ba82a

Please sign in to comment.