Qi

Cogito ergo sum

代码解析

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;
}
}
}

代码解析

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
package com.demo.s79;

/**
* 单词搜索
* 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
*
* 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/word-search
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class Solution {
public boolean exist(char[][] board, String word) {
int h = board.length, w = board[0].length;
boolean[][] visited = new boolean[h][w];
//遍历二维数组
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
//检查单词是否存在
boolean flag = check(board, visited, i, j, word, 0);
if (flag) {
return true;
}
}
}
return false;
}

public boolean check(char[][] board, boolean[][] visited, int i, int j, String s, int k) {
//对比字符,到达字符长度,递归结束条件
if (board[i][j] != s.charAt(k)) {
return false;
} else if (k == s.length() - 1) {
return true;
}
//标记为已访问过
visited[i][j] = true;
//上下左右四个方向查找
int[][] directions = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
boolean result = false;
for (int[] dir : directions) {
int newi = i + dir[0], newj = j + dir[1];
//边界判断
if (newi >= 0 && newi < board.length && newj >= 0 && newj < board[0].length) {
//没有访问过的网格,继续递归查找
if (!visited[newi][newj]) {
boolean flag = check(board, visited, newi, newj, s, k + 1);
if (flag) {
result = true;
break;
}
}
}
}
//没找到则标记为没有访问过,下次有可能组成新的单词时,再次访问
visited[i][j] = false;
return result;
}
}

代码解析

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.s78;

import java.util.ArrayList;
import java.util.List;

/**
* 子集
* 给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
*
* 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
*/
public class Solution {
List<Integer> t = new ArrayList<Integer>();
List<List<Integer>> ans = new ArrayList<List<Integer>>();

public List<List<Integer>> subsets(int[] nums) {
int n = nums.length;
for (int mask = 0; mask < (1 << n); ++mask) {
t.clear();
for (int i = 0; i < n; ++i) {
if ((mask & (1 << i)) != 0) {
t.add(nums[i]);
}
}
ans.add(new ArrayList<Integer>(t));
}
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
33
34
35
36
37
38
39
package com.demo.s77;

import java.util.ArrayList;
import java.util.List;

/**
* 组合
* 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
*
* 你可以按 任何顺序 返回答案。
*/
public class Solution {
List<Integer> temp = new ArrayList<Integer>();
List<List<Integer>> ans = new ArrayList<List<Integer>>();

public List<List<Integer>> combine(int n, int k) {
dfs(1, n, k);
return ans;
}

public void dfs(int cur, int n, int k) {
// 剪枝:temp 长度加上区间 [cur, n] 的长度小于 k,不可能构造出长度为 k 的 temp
if (temp.size() + (n - cur + 1) < k) {
return;
}
// 记录合法的答案
if (temp.size() == k) {
ans.add(new ArrayList<Integer>(temp));
return;
}
// 考虑选择当前位置
temp.add(cur);
dfs(cur + 1, n, k);
temp.remove(temp.size() - 1);
// 考虑不选择当前位置
dfs(cur + 1, n, k);
}

}

代码解析

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
package com.demo.s76;

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

/**
* 最小覆盖子串
* 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。
*
*  
*
* 注意:
*
* 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
* 如果 s 中存在这样的子串,我们保证它是唯一的答案。
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/minimum-window-substring
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class Solution {
//t 中每个字符出现的次数 存到 ori中
Map<Character, Integer> ori = new HashMap<Character, Integer>();
//记录字符串 s 子串中字符出现次数
Map<Character, Integer> cnt = new HashMap<Character, Integer>();

public String minWindow(String s, String t) {
int tLen = t.length();
//遍历t 统计出 ori
for (int i = 0; i < tLen; i++) {
char c = t.charAt(i);
ori.put(c, ori.getOrDefault(c, 0) + 1);
}
int l = 0, r = -1;
//子字符串长度len
int len = Integer.MAX_VALUE, ansL = -1, ansR = -1;
int sLen = s.length();
//子字符串从 0 开始 到 r
while (r < sLen) {
++r;
//如果 s字符串的字符出现了 t总字符
if (r < sLen && ori.containsKey(s.charAt(r))) {
//则累加值 放到cnt中计数
cnt.put(s.charAt(r), cnt.getOrDefault(s.charAt(r), 0) + 1);
}
//如果满足要求了,尝试缩短子串
while (check() && l <= r) {
//如果比当前最小长度len 还小 则 更新len
if (r - l + 1 < len) {
len = r - l + 1;
ansL = l;
ansR = l + len;
}
// l 左移 对应统计cnt中字符数字也要减1
if (ori.containsKey(s.charAt(l))) {
cnt.put(s.charAt(l), cnt.getOrDefault(s.charAt(l), 0) - 1);
}
++l;
}
}
//如果ansL 存在 则返回 子字符串
return ansL == -1 ? "" : s.substring(ansL, ansR);
}

public boolean check() {
//检查是否完全满足 t的字符及出现次数要求
Iterator iter = ori.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
Character key = (Character) entry.getKey();
Integer val = (Integer) entry.getValue();
if (cnt.getOrDefault(key, 0) < val) {
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
package com.demo.s75;

/**
* <p>给定一个包含红色、白色和蓝色、共&nbsp;<code>n</code><em> </em>个元素的数组<meta charset="UTF-8" />&nbsp;<code>nums</code>&nbsp;,<strong><a href="https://baike.baidu.com/item/%E5%8E%9F%E5%9C%B0%E7%AE%97%E6%B3%95" target="_blank">原地</a></strong>对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。</p>
*
* <p>我们使用整数 <code>0</code>、&nbsp;<code>1</code> 和 <code>2</code> 分别表示红色、白色和蓝色。</p>
*/
public class Solution {
public void sortColors(int[] nums) {
int n = nums.length;
int ptr = 0;
for (int i = 0; i < n; ++i) {
if (nums[i] == 0) {
int temp = nums[i];
nums[i] = nums[ptr];
nums[ptr] = temp;
++ptr;
}
}
for (int i = ptr; i < n; ++i) {
if (nums[i] == 1) {
int temp = nums[i];
nums[i] = nums[ptr];
nums[ptr] = temp;
++ptr;
}
}
}
}
0%