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

/**
* 只出现一次的数字 II
* 给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。
*
*/
public class Solution {
public int singleNumber(int[] nums) {
//最终的结果值
int res = 0;
//int类型有32位,统计每一位1的个数
for (int i = 0; i < 32; i++) {
//统计第i位中1的个数
int oneCount = 0;
for (int j = 0; j < nums.length; j++) {
oneCount += (nums[j] >>> i) & 1;
}
//如果1的个数不是3的倍数,说明那个只出现一次的数字
//的二进制位中在这一位是1
if (oneCount % 3 == 1)
res |= 1 << i;
}
return res;
}
}

代码解析

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

import java.util.HashMap;

/**
* 只出现一次的数字
* 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
*
* 说明:
*
* 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/single-number
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class Solution {
public int singleNumber(int[] nums) {
//特殊情况
if (nums.length == 1) {
return nums[0];
}
//HashMap
HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
//将其存入哈希表中,含义为,若该元素不存在则存入表中,并计数为1,若已经存在获取次数并加1.
for (int x : nums) {
map.put(x , map.getOrDefault(x,0) + 1);
}
//遍历出出现次数为1的情况
for (int y : map.keySet()) {
if(map.get(y) == 1){
return y;
}
}
return 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
package com.demo.s135;

/**
* 分发糖果
* n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。
*
* 你需要按照以下要求,给这些孩子分发糖果:
*
* 每个孩子至少分配到 1 个糖果。
* 相邻两个孩子评分更高的孩子会获得更多的糖果。
* 请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/candy
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class Solution {
public int candy(int[] ratings) {
int n = ratings.length;
int[] left = new int[n];
//从左到右发,最少给1个 分高就比右边多给一个
for (int i = 0; i < n; i++) {
if (i > 0 && ratings[i] > ratings[i - 1]) {
left[i] = left[i - 1] + 1;
} else {
left[i] = 1;
}
}
//从右向左,保证左侧分高的能多分一个糖
int right = 0, ret = 0;
for (int i = n - 1; i >= 0; i--) {
if (i < n - 1 && ratings[i] > ratings[i + 1]) {
right++;
} else {
right = 1;
}
ret += Math.max(left[i], right);
}
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
package com.demo.s134;

/**
* 加油站
* 在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。
*
* 你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。
*
* 给定两个整数数组 gas 和 cost ,如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1 。如果存在解,则 保证 它是 唯一 的。
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/gas-station
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int n = gas.length;
int i = 0;
while (i < n) {
int sumOfGas = 0, sumOfCost = 0;
int cnt = 0;
while (cnt < n) {
int j = (i + cnt) % n;
sumOfGas += gas[j];
sumOfCost += cost[j];
if (sumOfCost > sumOfGas) {
break;
}
cnt++;
}
if (cnt == n) {
return i;
} else {
i = i + cnt + 1;
}
}
return -1;
}
}

代码解析

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

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

/**
* 克隆图
* 给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。
*
* 图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[Node])。
*
* class Node {
* public int val;
* public List<Node> neighbors;
* }
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/clone-graph
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/

class Node {
public int val;
public List<Node> neighbors;
public Node() {
val = 0;
neighbors = new ArrayList<Node>();
}
public Node(int _val) {
val = _val;
neighbors = new ArrayList<Node>();
}
public Node(int _val, ArrayList<Node> _neighbors) {
val = _val;
neighbors = _neighbors;
}
}

public class Solution {
private HashMap<Node, Node> visited = new HashMap <> ();
public Node cloneGraph(Node node) {
if (node == null) {
return node;
}

// 如果该节点已经被访问过了,则直接从哈希表中取出对应的克隆节点返回
if (visited.containsKey(node)) {
return visited.get(node);
}

// 克隆节点,注意到为了深拷贝我们不会克隆它的邻居的列表
Node cloneNode = new Node(node.val, new ArrayList());
// 哈希表存储
visited.put(node, cloneNode);

// 遍历该节点的邻居并更新克隆节点的邻居列表
for (Node neighbor: node.neighbors) {
cloneNode.neighbors.add(cloneGraph(neighbor));
}
return cloneNode;
}

}

代码解析

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

import java.util.Arrays;

/**
* 分割回文串 II
* 给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文。
*
* 返回符合要求的 最少分割次数 。
*
*/
public class Solution {
public int minCut(String s) {
int n = s.length();
boolean[][] g = new boolean[n][n];
for (int i = 0; i < n; ++i) {
Arrays.fill(g[i], true);
}

for (int i = n - 1; i >= 0; --i) {
for (int j = i + 1; j < n; ++j) {
g[i][j] = s.charAt(i) == s.charAt(j) && g[i + 1][j - 1];
}
}

int[] f = new int[n];
Arrays.fill(f, Integer.MAX_VALUE);
for (int i = 0; i < n; ++i) {
if (g[0][i]) {
f[i] = 0;
} else {
for (int j = 0; j < i; ++j) {
if (g[j + 1][i]) {
f[i] = Math.min(f[i], f[j] + 1);
}
}
}
}

return f[n - 1];
}
}

代码解析

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

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

/**
* 分割回文串
* 给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。
*
* 回文串 是正着读和反着读都一样的字符串。
*/
public class Solution {
boolean[][] f;
List<List<String>> ret = new ArrayList<List<String>>();
List<String> ans = new ArrayList<String>();
int n;

public List<List<String>> partition(String s) {
n = s.length();
f = new boolean[n][n];
for (int i = 0; i < n; ++i) {
Arrays.fill(f[i], true);
}

for (int i = n - 1; i >= 0; --i) {
for (int j = i + 1; j < n; ++j) {
f[i][j] = (s.charAt(i) == s.charAt(j)) && f[i + 1][j - 1];
}
}

dfs(s, 0);
return ret;
}

public void dfs(String s, int i) {
if (i == n) {
ret.add(new ArrayList<String>(ans));
return;
}
for (int j = i; j < n; ++j) {
if (f[i][j]) {
ans.add(s.substring(i, j + 1));
dfs(s, j + 1);
ans.remove(ans.size() - 1);
}
}
}
}

代码解析

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

/**
* 被围绕的区域
* 给你一个 m x n 的矩阵 board ,由若干字符 'X' 和 'O' ,找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。
*
*/
public class Solution {
int n, m;

public void solve(char[][] board) {
n = board.length;
if (n == 0) {
return;
}
m = board[0].length;
for (int i = 0; i < n; i++) {
dfs(board, i, 0);
dfs(board, i, m - 1);
}
for (int i = 1; i < m - 1; i++) {
dfs(board, 0, i);
dfs(board, n - 1, i);
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (board[i][j] == 'A') {
board[i][j] = 'O';
} else if (board[i][j] == 'O') {
board[i][j] = 'X';
}
}
}
}

public void dfs(char[][] board, int x, int y) {
if (x < 0 || x >= n || y < 0 || y >= m || board[x][y] != 'O') {
return;
}
board[x][y] = 'A';
dfs(board, x + 1, y);
dfs(board, x - 1, y);
dfs(board, x, y + 1);
dfs(board, x, y - 1);
}
}

代码解析

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

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

/**
* 罗马数字转整数
* 例如, 罗马数字 2 写做 II ,即为两个并列的 1 。12 写做 XII ,即为 X + II 。 27 写做  XXVII, 即为 XX + V + II 。
*
* 通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
*
* I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
* X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。 
* C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
* 给定一个罗马数字,将其转换成整数。
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/roman-to-integer
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class Solution {
Map<Character, Integer> symbolValues = new HashMap<Character, Integer>() {{
put('I', 1);
put('V', 5);
put('X', 10);
put('L', 50);
put('C', 100);
put('D', 500);
put('M', 1000);
}};

public int romanToInt(String s) {
int ans = 0;
int n = s.length();
for (int i = 0; i < n; ++i) {
int value = symbolValues.get(s.charAt(i));
if (i < n - 1 && value < symbolValues.get(s.charAt(i + 1))) {
ans -= value;
} else {
ans += value;
}
}
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
40
41
42
43
44
45
46
47
48
49
50
51
package com.demo.s129;

/**
* 求根节点到叶节点数字之和
* 给你一个二叉树的根节点 root ,树中每个节点都存放有一个 0 到 9 之间的数字。
* 每条从根节点到叶节点的路径都代表一个数字:
*
* 例如,从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。
* 计算从根节点到叶节点生成的 所有数字之和 。
*
* 叶节点 是指没有子节点的节点。
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/sum-root-to-leaf-numbers
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/

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

public class Solution {
public int sumNumbers(TreeNode root) {
//深度遍历 累加数字
return dfs(root, 0);
}

public int dfs(TreeNode root, int prevSum) {
if (root == null) {
return 0;
}
//累加数字,每位进10
int sum = prevSum * 10 + root.val;
//左右子树为null 则返回和
if (root.left == null && root.right == null) {
return sum;
} else {
//继续深度遍历
return dfs(root.left, sum) + dfs(root.right, sum);
}
}
}
0%