0%

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.demo.s88;

/**
* 合并两个有序数组
* 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
*
* 请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
*
* 注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
*
*
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/merge-sorted-array
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
//定义新数组
int[] all = new int[m + n];
int i = 0;
int j = 0;
while(i< m || j < n) {
int cur;
//num1遍历完了,遍历num2
if(i == m) {
cur = nums2[j++];
//num2遍历完了,遍历num1
} else if(j == n) {
cur = nums1[i++];
//小的元素先排上
} else if(nums1[i] <= nums2[j]) {
cur = nums1[i++];
} else {
cur = nums2[j++];
}
all[i+j-1] = cur;
}
//新数组元素再放到num1中
for(int t = 0; t< n + m; t++) {
nums1[t] = all[t];
}
}
}

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package com.demo.s87;

import java.util.HashMap;
import java.util.Map;

/**
* 扰乱字符串
* 使用下面描述的算法可以扰乱字符串 s 得到字符串 t :
* 如果字符串的长度为 1 ,算法停止
* 如果字符串的长度 > 1 ,执行下述步骤:
* 在一个随机下标处将字符串分割成两个非空的子字符串。即,如果已知字符串 s ,则可以将其分成两个子字符串 x 和 y ,且满足 s = x + y 。
* 随机 决定是要「交换两个子字符串」还是要「保持这两个子字符串的顺序不变」。即,在执行这一步骤之后,s 可能是 s = x + y 或者 s = y + x 。
* 在 x 和 y 这两个子字符串上继续从步骤 1 开始递归执行此算法。
* 给你两个 长度相等 的字符串 s1 和 s2,判断 s2 是否是 s1 的扰乱字符串。如果是,返回 true ;否则,返回 false 。
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/scramble-string
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class Solution {
// 记忆化搜索存储状态的数组
// -1 表示 false,1 表示 true,0 表示未计算
int[][][] memo;
String s1, s2;

public boolean isScramble(String s1, String s2) {
int length = s1.length();
this.memo = new int[length][length][length + 1];
this.s1 = s1;
this.s2 = s2;
return dfs(0, 0, length);
}

// 第一个字符串从 i1 开始,第二个字符串从 i2 开始,子串的长度为 length,是否和谐
public boolean dfs(int i1, int i2, int length) {
if (memo[i1][i2][length] != 0) {
return memo[i1][i2][length] == 1;
}

// 判断两个子串是否相等
if (s1.substring(i1, i1 + length).equals(s2.substring(i2, i2 + length))) {
memo[i1][i2][length] = 1;
return true;
}

// 判断是否存在字符 c 在两个子串中出现的次数不同
if (!checkIfSimilar(i1, i2, length)) {
memo[i1][i2][length] = -1;
return false;
}

// 枚举分割位置
for (int i = 1; i < length; ++i) {
// 不交换的情况
if (dfs(i1, i2, i) && dfs(i1 + i, i2 + i, length - i)) {
memo[i1][i2][length] = 1;
return true;
}
// 交换的情况
if (dfs(i1, i2 + length - i, i) && dfs(i1 + i, i2, length - i)) {
memo[i1][i2][length] = 1;
return true;
}
}

memo[i1][i2][length] = -1;
return false;
}

public boolean checkIfSimilar(int i1, int i2, int length) {
Map<Character, Integer> freq = new HashMap<Character, Integer>();
for (int i = i1; i < i1 + length; ++i) {
char c = s1.charAt(i);
freq.put(c, freq.getOrDefault(c, 0) + 1);
}
for (int i = i2; i < i2 + length; ++i) {
char c = s2.charAt(i);
freq.put(c, freq.getOrDefault(c, 0) - 1);
}
for (Map.Entry<Character, Integer> entry : freq.entrySet()) {
int value = entry.getValue();
if (value != 0) {
return false;
}
}
return true;
}
}

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.demo.s86;

/**
* 分隔链表
* 给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。
*
* 你应当 保留 两个分区中每个节点的初始相对位置。
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/partition-list
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
public class Solution {

public ListNode partition(ListNode head, int x) {
ListNode lessHead = new ListNode(0);
ListNode moreHead = new ListNode(0);

if(head == null) return null;
ListNode cur = head;
ListNode curLess = lessHead;
ListNode curMore = moreHead;

while(cur != null)
{
if(cur.val < x)
{
curLess.next = new ListNode(cur.val);
curLess = curLess.next;
cur = cur.next;
}
else
{
curMore.next = new ListNode(cur.val);
curMore = curMore.next;
cur = cur.next;
}
}
curLess.next = moreHead.next;
return lessHead.next;
}


}

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package com.demo.s85;

import java.util.Deque;
import java.util.LinkedList;

/**
* 最大矩形
* 给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
*/
public class Solution {
public int maximalRectangle(char[][] matrix) {
int m = matrix.length;
if (m == 0) {
return 0;
}
int n = matrix[0].length;
int[][] left = new int[m][n];

for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == '1') {
left[i][j] = (j == 0 ? 0 : left[i][j - 1]) + 1;
}
}
}

int ret = 0;
for (int j = 0; j < n; j++) { // 对于每一列,使用基于柱状图的方法
int[] up = new int[m];
int[] down = new int[m];

Deque<Integer> stack = new LinkedList<Integer>();
for (int i = 0; i < m; i++) {
while (!stack.isEmpty() && left[stack.peek()][j] >= left[i][j]) {
stack.pop();
}
up[i] = stack.isEmpty() ? -1 : stack.peek();
stack.push(i);
}
stack.clear();
for (int i = m - 1; i >= 0; i--) {
while (!stack.isEmpty() && left[stack.peek()][j] >= left[i][j]) {
stack.pop();
}
down[i] = stack.isEmpty() ? m : stack.peek();
stack.push(i);
}

for (int i = 0; i < m; i++) {
int height = down[i] - up[i] - 1;
int area = height * left[i][j];
ret = Math.max(ret, area);
}
}
return ret;
}
}

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.demo.s84;

import java.util.Stack;

/**
* 柱状图中最大的矩形
* 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
*
* 求在该柱状图中,能够勾勒出来的矩形的最大面积。
*/
public class Solution {
public int largestRectangleArea(int[] heights) {
int n = heights.length;
int[] left = new int[n];
int[] right = new int[n];

Stack<Integer> mono_stack = new Stack<Integer>();
for (int i = 0; i < n; ++i) {
while (!mono_stack.isEmpty() && heights[mono_stack.peek()] >= heights[i]) {
mono_stack.pop();
}
left[i] = (mono_stack.isEmpty() ? -1 : mono_stack.peek());
mono_stack.push(i);
}

mono_stack.clear();
for (int i = n - 1; i >= 0; --i) {
while (!mono_stack.isEmpty() && heights[mono_stack.peek()] >= heights[i]) {
mono_stack.pop();
}
right[i] = (mono_stack.isEmpty() ? n : mono_stack.peek());
mono_stack.push(i);
}

int ans = 0;
for (int i = 0; i < n; ++i) {
ans = Math.max(ans, (right[i] - left[i] - 1) * heights[i]);
}
return ans;

}
}

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.demo.s83;

/**
* 删除排序链表中的重复元素
* 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。
*/
class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}

public class Solution {
public ListNode deleteDuplicates(ListNode head) {
if (head == null) {
return head;
}

ListNode cur = head;
while (cur.next != null) {
if (cur.val == cur.next.val) {
cur.next = cur.next.next;
} else {
cur = cur.next;
}
}

return head;
}
}

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.demo.s82;

/**
* 删除排序链表中的重复元素 II
* 给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。
*/
class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}

public class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode dum = new ListNode();
dum.next = head;
if(head == null) {
return head;
}

ListNode cur = dum;
while(cur.next != null && cur.next.next != null) {
if (cur.next.val == cur.next.next.val) {
int x = cur.next.val;
while (cur.next != null && cur.next.val == x) {
cur.next = cur.next.next;
}
} else {
cur = cur.next;
}
}
return dum.next;
}
}

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package com.demo.s81;

/**
* 搜索旋转排序数组 II
* 已知存在一个按非降序排列的整数数组 nums ,数组中的值不必互不相同。
*
* 在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转 ,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,4,4,5,6,6,7] 在下标 5 处经旋转后可能变为 [4,5,6,6,7,0,1,2,4,4] 。
*
* 给你 旋转后 的数组 nums 和一个整数 target ,请你编写一个函数来判断给定的目标值是否存在于数组中。如果 nums 中存在这个目标值 target ,则返回 true ,否则返回 false 。
*
* 你必须尽可能减少整个操作步骤。
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/search-in-rotated-sorted-array-ii
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class Solution {
public boolean search(int[] nums, int target) {
if (nums == null || nums.length == 0) {
return false;
}
int start = 0;
int end = nums.length - 1;
int mid;
while (start <= end) {
mid = start + (end - start) / 2;
if (nums[mid] == target) {
return true;
}
if (nums[start] == nums[mid]) {
start++;
continue;
}
//前半部分有序
if (nums[start] < nums[mid]) {
//target在前半部分
if (nums[mid] > target && nums[start] <= target) {
end = mid - 1;
} else { //否则,去后半部分找
start = mid + 1;
}
} else {
//后半部分有序
//target在后半部分
if (nums[mid] < target && nums[end] >= target) {
start = mid + 1;
} else { //否则,去后半部分找
end = mid - 1;

}
}
}
//一直没找到,返回false
return false;

}
}

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.demo.s80;

/**
* 删除有序数组中的重复项 II
* 给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。
*
* 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class Solution {
public int removeDuplicates(int[] nums) {
int n = nums.length;
if (n <= 2) {
return n;
}
int slow = 2, fast = 2;
while (fast < n) {
if (nums[slow - 2] != nums[fast]) {
nums[slow] = nums[fast];
++slow;
}
++fast;
}
return slow;
}
}

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package com.demo.s8;

import java.util.HashMap;

/**
* 字符串转换整数 (atoi)
* 请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。
*
* 函数 myAtoi(string s) 的算法如下:
*
* 读入字符串并丢弃无用的前导空格
* 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
* 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
* 将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
* 如果整数数超过 32 位有符号整数范围 [−231,  231 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,大于 231 − 1 的整数应该被固定为 231 − 1 。
* 返回整数作为最终结果。
* 注意:
*
* 本题中的空白字符只包括空格字符 ' ' 。
* 除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。
*
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/string-to-integer-atoi
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class Solution {
public int myAtoi(String s) {
// 自动机
HashMap<String, String[]> map = new HashMap();
map.put("start", new String[]{"start", "signed", "number", "end"});
map.put("signed", new String[]{"end", "end", "number", "end"});
map.put("number", new String[]{"end", "end", "number", "end"});
map.put("end", new String[]{"end", "end", "end", "end"});
//第一步开始
String step = "start";
long num = 0;
int sign = 1;
for(int i = 0;i < s.length() && !step.equals("end"); i++) {
char ch = s.charAt(i);
int n = getChar(ch);
//下一步,根据上一步和当前字符 匹配 自动机 得出
step = map.get(step)[n];
if("number".equals(step)) {
num = num * 10 + (ch - '0');
num = sign == 1 ? Math.min(num, (long)Integer.MAX_VALUE) : Math.min(num, -1 * (long)Integer.MIN_VALUE);
} else if("signed".equals(step)) {
sign = (ch == '+') ? 1 : -1;
} else if("signed".equals(step)) {
return 0;
}
}
return sign * (int)num;

}

private int getChar(char ch) {
if(' ' == ch) {
return 0;
} else if('+' == ch || '-' == ch) {
return 1;
} else if(0 <= ch-'0' && ch-'0' <= 9) {
return 2;
} else {
return 3;
}
}
}