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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package com.demo.s74;

/**
* <p>编写一个高效的算法来判断 <code>m x n</code> 矩阵中,是否存在一个目标值。该矩阵具有如下特性:</p>
*
* <ul>
* <li>每行中的整数从左到右按升序排列。</li>
* <li>每行的第一个整数大于前一行的最后一个整数。</li>
* </ul>
*
*/
public class Solution {

public boolean searchMatrix(int[][] matrix, int target) {
int rowIndex = binarySearchFirstColumn(matrix, target);
if (rowIndex < 0) {
return false;
}
return binarySearchRow(matrix[rowIndex], target);
}

public int binarySearchFirstColumn(int[][] matrix, int target) {
int low = -1, high = matrix.length - 1;
while (low < high) {
int mid = (high - low + 1) / 2 + low;
if (matrix[mid][0] <= target) {
low = mid;
} else {
high = mid - 1;
}
}
return low;
}

public boolean binarySearchRow(int[] row, int target) {
int low = 0, high = row.length - 1;
while (low <= high) {
int mid = (high - low) / 2 + low;
if (row[mid] == target) {
return true;
} else if (row[mid] > target) {
high = mid - 1;
} else {
low = mid + 1;
}
}
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
package com.demo.s73;

/**
* 矩阵置零
* <p>给定一个&nbsp;<code><em>m</em> x <em>n</em></code> 的矩阵,如果一个元素为 <strong>0 </strong>,则将其所在行和列的所有元素都设为 <strong>0</strong> 。请使用 <strong><a href="http://baike.baidu.com/item/%E5%8E%9F%E5%9C%B0%E7%AE%97%E6%B3%95" target="_blank">原地</a></strong> 算法<strong>。</strong></p>
*/
public class Solution {
public void setZeroes(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
boolean[] row = new boolean[m];
boolean[] col = new boolean[n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == 0) {
row[i] = col[j] = true;
}
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (row[i] || col[j]) {
matrix[i][j] = 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
package com.demo.s72;

/**
* 编辑距离
*/
public class Solution {
public int minDistance(String word1, String word2) {
int m = word1.length();
int n = word2.length();

if(m == 0 || n == 0) {
return m + n;
}
int[][] dp = new int[m + 1][n + 1];
//j == 0 也就是 words2 长度为0时,编辑距离 完全取决于words1长度
for(int i = 0; i< m + 1; i++) {
dp[i][0] = i;
}
//i == 0 也就是 words1 长度为0时,编辑距离 完全取决于words2长度
for(int j = 0; j< n + 1; j++) {
dp[0][j] = j;
}

for(int i = 1; i<= m; i++) {
for(int j = 1; j<= n; j++) {
//字符相等 则编辑距离不变
if(word1.charAt(i-1) == word2.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1];
} else {
//取决于前者编辑距离的最小值 + 1
dp[i][j] = Math.min(dp[i-1][j], Math.min(dp[i][j-1], dp[i-1][j-1])) + 1;
}
}
}
return dp[m][n];
}
}

代码解析

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


/**
*给两个整数数组 nums1 和 nums2 ,返回 两个数组中 公共的 、长度最长的子数组的长度 。
*/
public class Solution {
public int findLength(int[] A, int[] B) {
return A.length < B.length ? findMax(A, B) : findMax(B, A);
}

int findMax(int[] A, int[] B) {
int max = 0;
int an = A.length, bn = B.length;
for(int len=1; len <= an; len++) {
max = Math.max(max, maxLen(A, 0, B, bn - len, len));
}
for(int j=bn-an; j >= 0;j--) {
max = Math.max(max, maxLen(A, 0, B, j, an));
}
for(int i=1;i<an;i++) {
max = Math.max(max, maxLen(A, i, B, 0, an - i));
}
return max;
}

int maxLen(int[] a, int i, int[] b, int j, int len) {
int count = 0, max = 0;
for(int k = 0; k < len; k++) {
if(a[i+k] == b[j+k]) {
count++;
} else if(count > 0) {
max = Math.max(max, count);
count = 0;
}
}
return count > 0 ? Math.max(max, count) : max;
}
}

代码解析

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

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

/**
* 简化路径
* 给你一个字符串 path ,表示指向某一文件或目录的 Unix 风格 绝对路径 (以 '/' 开头),请你将其转化为更加简洁的规范路径。
*
* 在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。任意多个连续的斜杠(即,'//')都被视为单个斜杠 '/' 。 对于此问题,任何其他格式的点(例如,'...')均被视为文件/目录名称。
*
* 请注意,返回的 规范路径 必须遵循下述格式:
*
* 始终以斜杠 '/' 开头。
* 两个目录名之间必须只有一个斜杠 '/' 。
* 最后一个目录名(如果存在)不能 以 '/' 结尾。
* 此外,路径仅包含从根目录到目标文件或目录的路径上的目录(即,不含 '.' 或 '..')。
* 返回简化后得到的 规范路径 。
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/simplify-path
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class Solution {
public String simplifyPath(String path) {
// 双端队列
Deque<String> queue = new LinkedList<>();
// 分割字符
String[] res = path.split("/");
for(int i = 0; i < res.length; i++){
String s = res[i];
if(s.equals(".") || s.equals("")) continue;
else if (s.equals("..")){
if(!queue.isEmpty()){
queue.pollLast();
}
}else{
queue.offer(s);
}
}
// 拼接
StringBuilder sb = new StringBuilder("/");
while(!queue.isEmpty()){
sb.append(queue.poll());
if(!queue.isEmpty()){
sb.append("/");
}
}
// 判空
return sb.toString().equals("") ? "/" : sb.toString();
}
}

代码解析

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


/**
*给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。
*
* 你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。
*
*  
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/add-strings
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class Solution {
public String addStrings(String num1, String num2) {
//字符串拼接 StringBuilder
StringBuilder builder = new StringBuilder();
int m = num1.length();
int n = num2.length();
//num1 遍历 下标
int i =1;
//num2 遍历 下标
int j =1;
int carray = 0;

while(i + j <= m + n + 1) {
int numa = 0;
//补0对齐位数
if(i > m) {
numa = 0;
} else {
//字符转数字 从右向左 取值
numa = num1.charAt(m - i++) - '0';
}
int numb = 0;
//补0对齐位数
if(j > n) {
numb = 0;
} else {
//字符转数字 从右向左 取值
numb = num2.charAt(n - j++) - '0';
}
//从右向左 逐位数字相加
int sum = numa + numb + carray;
//满10 进一位
carray = sum / 10;
builder.append(sum % 10);
}
//最后一次相加后 如果有进位 则拼接到字符串
if(carray != 0) {
builder.append(carray);
}
//翻转字符串
return builder.reverse().toString();
}
}

代码解析

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

/**
* 爬楼梯
* 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
*
* 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
*/
public class Solution {
public int climbStairs(int n) {
//倒推 func(n) = func(n-1) + func(n-2)
//边界 func(3) = func(2) + func(1)
// func(2) = 2
// func(1) = 1
// func(0) = 0
int p = 0;
int q = 0;
int r = 1;
for(int i =0; i< n; i++) {
p = q;
q = r;
r = p + q;
}
return r;
}
}

代码解析

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

/**
* 整数反转
* 给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
*
* 如果反转后整数超过 32 位的有符号整数的范围 [−231,  231 − 1] ,就返回 0。
*
* 假设环境不允许存储 64 位整数(有符号或无符号)
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/reverse-integer
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class Solution {
public int reverse(int x) {
//初始化返回值
int res = 0;
//数字拆分
while(x != 0) {
//特殊情况判断
if(res < Integer.MIN_VALUE/10 || res > Integer.MAX_VALUE/10) {
return 0;
}
int m = x % 10;
x = x / 10;
res = res * 10 + m;
}

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
39
40
package com.demo.s69;

/**
* x平方根
* 给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
*
* 由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
*
* 注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。
*
*
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/sqrtx
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class Solution {
public int mySqrt(int x) {
int l = 0;
int r = x;
int ret = 0;
//中间值 二分法
int mid = 0;
//左右移动 l r
while(l <= r) {
mid = (l + r)/ 2;
long tmp = (long)mid * mid;
if(tmp == x) {
return mid;
}
if(tmp <= x) {
ret = mid;
l = mid + 1;
} else {
r = mid - 1;
}
}
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
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
package com.demo.s68;

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

/**
* 文本左右对齐
* 给定一个单词数组 words 和一个长度 maxWidth ,重新排版单词,使其成为每行恰好有 maxWidth 个字符,且左右两端对齐的文本。
*
* 你应该使用 “贪心算法” 来放置给定的单词;也就是说,尽可能多地往每行中放置单词。必要时可用空格 ' ' 填充,使得每行恰好有 maxWidth 个字符。
*
* 要求尽可能均匀分配单词间的空格数量。如果某一行单词间的空格不能均匀分配,则左侧放置的空格数要多于右侧的空格数。
*
* 文本的最后一行应为左对齐,且单词之间不插入额外的空格。
*
* 注意:
*
* 单词是指由非空格字符组成的字符序列。
* 每个单词的长度大于 0,小于等于 maxWidth。
* 输入单词数组 words 至少包含一个单词。
*
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/text-justification
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class Solution {
public List<String> fullJustify(String[] words, int maxWidth) {
//定义0-maxWidth个空格字符串,方便之后直接调用
final String[] space = new String[maxWidth+1];
StringBuffer s = new StringBuffer();
for(int i = 0;i<maxWidth+1;i++){
space[i] = s.toString();
s.append(" ");
}
//新建List,用来存最后的结果。
List<String> pWords = new ArrayList<String>();
//遍历整个words,一行一行的排版
for(int i=0; i<words.length; i++){
int curlen = words[i].length();
//记录当前已读取单词的长度,当>=maxWidth时进行排版
int startI = i;
//记录本次读取单词的起点
while(i < words.length-1 && curlen<maxWidth){
i++;
curlen = curlen+words[i].length()+1;
// 每多读一个单词都要加一个空格
}
if(curlen>maxWidth){
//当前长度>maxWidth,说明已经多读取了一个单词
curlen = curlen-words[i].length()-1;
i--;
}
//一行一行的排版
pWords.add(processCurline(words,startI,i,curlen,maxWidth,space));
}
return pWords;
}
public String processCurline(String[] words,int si,int ei,int curlen,int maxWidth,String[] space){
StringBuffer sb = new StringBuffer(); //用来进行排版
int map = ei-si; // 记录单词之间的有几个间隙
int addSpace = maxWidth - curlen+map; //记录这一行总共有多少个空格
if(map==0){ //间隙为0,证明只有一个单词
sb.append(words[ei]);
sb.append(space[addSpace]);
return sb.toString();
}
if(ei == words.length-1){ //证明要排版最后一行了,格式特殊
for(int i =si;i<ei;i++){
sb.append(words[i]).append(" ");
}
sb.append(words[ei]); //最后一个单词不用加空格
sb.append(space[addSpace-map]); //如果还有多余空格,一起加上
return sb.toString();
}
int allAddSpace = addSpace/map; //所有的空格数 / 间隙 = 每个间隙必加的空格数
int left = addSpace % map + si; //多出来的空格要从si开始,依次加在间隙中
for(int i = si;i<ei;i++){
sb.append(words[i]).append(space[allAddSpace]);
if(i < left) sb.append(" "); // <left就要多加一个空格
}
sb.append(words[ei]);
return sb.toString();
}
}
0%