@@ -909,15 +909,15 @@ public ListNode deleteNode(ListNode head, ListNode tobeDelete) {
909
909
910
910
``` java
911
911
public ListNode deleteDuplication(ListNode pHead) {
912
- if (pHead == null ) return null ;
912
+ if (pHead == null || pHead . next == null ) return pHead ;
913
913
ListNode next = pHead. next;
914
- if (next == null ) return pHead;
915
914
if (pHead. val == next. val) {
916
915
while (next != null && pHead. val == next. val) next = next. next;
917
916
return deleteDuplication(next);
917
+ } else {
918
+ pHead. next = deleteDuplication(pHead. next);
919
+ return pHead;
918
920
}
919
- pHead. next = deleteDuplication(pHead. next);
920
- return pHead;
921
921
}
922
922
```
923
923
@@ -2256,6 +2256,8 @@ private int height(TreeNode root) {
2256
2256
2257
2257
## 题目描述
2258
2258
2259
+ [ NowCoder] ( https://www.nowcoder.com/practice/e02fdb54d7524710a7d664d082bb7811?tpId=13&tqId=11193&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking )
2260
+
2259
2261
一个整型数组里除了两个数字之外,其他的数字都出现了两次,找出这两个数。
2260
2262
2261
2263
## 解题思路
@@ -2267,73 +2269,91 @@ private int height(TreeNode root) {
2267
2269
diff &= -diff 得到出 diff 最右侧不为 0 的位,也就是不存在重复的两个元素在位级表示上最右侧不同的那一位,利用这一位就可以将两个元素区分开来。
2268
2270
2269
2271
``` java
2270
- public void FindNumsAppearOnce(int [] array, int num1[], int num2[]) {
2271
- int diff = 0 ;
2272
- for (int num : array) diff ^ = num;
2273
- // 得到最右一位
2274
- diff &= - diff;
2275
- for (int num : array) {
2276
- if ((num & diff) == 0 ) num1[0 ] ^ = num;
2277
- else num2[0 ] ^ = num;
2272
+ public void FindNumsAppearOnce(int [] nums, int num1[], int num2[]) {
2273
+ int diff = 0 ;
2274
+ for (int num : nums) {
2275
+ diff ^ = num;
2276
+ }
2277
+ // 得到最右一位
2278
+ diff &= - diff;
2279
+ for (int num : nums) {
2280
+ if ((num & diff) == 0 ) {
2281
+ num1[0 ] ^ = num;
2282
+ } else {
2283
+ num2[0 ] ^ = num;
2284
+ }
2285
+ }
2278
2286
}
2279
- }
2280
2287
```
2281
2288
2282
2289
# 57.1 和为 S 的两个数字
2283
2290
2284
2291
## 题目描述
2285
2292
2293
+ [ NowCoder] ( https://www.nowcoder.com/practice/390da4f7a00f44bea7c2f3d19491311b?tpId=13&tqId=11195&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking )
2294
+
2286
2295
输入一个递增排序的数组和一个数字 S,在数组中查找两个数,使得他们的和正好是 S,如果有多对数字的和等于 S,输出两个数的乘积最小的。
2287
2296
2288
2297
## 解题思路
2289
2298
2290
2299
使用双指针,一个指针指向元素较小的值,一个指针指向元素较大的值。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。
2291
2300
2292
- 如果两个指针指向元素的和 sum == target,那么得到要求的结果;如果 sum > target,移动较大的元素,使 sum 变小一些;如果 sum < target,移动较小的元素,使 sum 变大一些。
2301
+ - 如果两个指针指向元素的和 sum == target,那么得到要求的结果;
2302
+ - 如果 sum > target,移动较大的元素,使 sum 变小一些;
2303
+ - 如果 sum < target,移动较小的元素,使 sum 变大一些。
2293
2304
2294
2305
``` java
2295
2306
public ArrayList<Integer > FindNumbersWithSum(int [] array, int sum) {
2296
2307
int i = 0 , j = array. length - 1 ;
2297
2308
while (i < j) {
2298
2309
int cur = array[i] + array[j];
2299
- if (cur == sum) return new ArrayList<Integer > (Arrays . asList(array[i], array[j]));
2300
- else if (cur < sum) i++ ;
2310
+ if (cur == sum) return new ArrayList<> (Arrays . asList(array[i], array[j]));
2311
+ if (cur < sum) i++ ;
2301
2312
else j-- ;
2302
2313
}
2303
- return new ArrayList<Integer > ();
2314
+ return new ArrayList<> ();
2304
2315
}
2305
2316
```
2306
2317
2307
2318
# 57.2 和为 S 的连续正数序列
2308
2319
2309
2320
## 题目描述
2310
2321
2311
- 和为 100 的连续序列有 18, 19, 20, 21, 22。
2322
+ [ NowCoder] ( https://www.nowcoder.com/practice/c451a3fd84b64cb19485dad758a55ebe?tpId=13&tqId=11194&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking )
2323
+
2324
+ 输出所有和为 S 的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
2325
+
2326
+ 例如和为 100 的连续序列有:
2327
+
2328
+ ```
2329
+ [9, 10, 11, 12, 13, 14, 15, 16]
2330
+ [18, 19, 20, 21, 22]。
2331
+ ```
2312
2332
2313
2333
## 解题思路
2314
2334
2315
2335
``` java
2316
2336
public ArrayList<ArrayList<Integer > > FindContinuousSequence(int sum) {
2317
2337
ArrayList<ArrayList<Integer > > ret = new ArrayList<> ();
2318
- int first = 1 , last = 2 ;
2338
+ int start = 1 , end = 2 ;
2319
2339
int curSum = 3 ;
2320
- while (first <= sum / 2 && last < sum) {
2340
+ while (end < sum) {
2321
2341
if (curSum > sum) {
2322
- curSum -= first ;
2323
- first ++ ;
2342
+ curSum -= start ;
2343
+ start ++ ;
2324
2344
} else if (curSum < sum) {
2325
- last ++ ;
2326
- curSum += last ;
2345
+ end ++ ;
2346
+ curSum += end ;
2327
2347
} else {
2328
2348
ArrayList<Integer > list = new ArrayList<> ();
2329
- for (int i = first ; i <= last ; i++ ) {
2349
+ for (int i = start ; i <= end ; i++ ) {
2330
2350
list. add(i);
2331
2351
}
2332
2352
ret. add(list);
2333
- curSum -= first ;
2334
- first ++ ;
2335
- last ++ ;
2336
- curSum += last ;
2353
+ curSum -= start ;
2354
+ start ++ ;
2355
+ end ++ ;
2356
+ curSum += end ;
2337
2357
}
2338
2358
}
2339
2359
return ret;
@@ -2350,11 +2370,14 @@ public ArrayList<ArrayList<Integer>> FindContinuousSequence(int sum) {
2350
2370
2351
2371
## 解题思路
2352
2372
2353
- 题目应该有一个隐含条件,就是不能用额外的空间。虽然 Java 的题目输入参数为 String 类型,需要先创建一个字符数组使得空间复杂度为 O(n),但是正确的参数类型应该和原书一样,为字符数组,并且只能使用该字符数组的空间。任何使用了额外空间的解法在面试时都会大打折扣,包括递归解法。正确的解法应该是和书上一样,先旋转每个单词,再旋转整个字符串。
2373
+ [ NowCoder] ( https://www.nowcoder.com/practice/3194a4f4cf814f63919d0790578d51f3?tpId=13&tqId=11197&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking )
2374
+
2375
+ 题目应该有一个隐含条件,就是不能用额外的空间。虽然 Java 的题目输入参数为 String 类型,需要先创建一个字符数组使得空间复杂度为 O(N),但是正确的参数类型应该和原书一样,为字符数组,并且只能使用该字符数组的空间。任何使用了额外空间的解法在面试时都会大打折扣,包括递归解法。
2376
+
2377
+ 正确的解法应该是和书上一样,先旋转每个单词,再旋转整个字符串。
2354
2378
2355
2379
``` java
2356
2380
public String ReverseSentence(String str) {
2357
- if (str. length() == 0 ) return str;
2358
2381
int n = str. length();
2359
2382
char [] chars = str. toCharArray();
2360
2383
int i = 0 , j = 0 ;
@@ -2370,58 +2393,73 @@ public String ReverseSentence(String str) {
2370
2393
}
2371
2394
2372
2395
private void reverse(char [] c, int i, int j) {
2373
- while (i < j) {
2374
- char t = c[i]; c[i] = c[j]; c[j] = t;
2375
- i++ ; j-- ;
2396
+ while (i < j) {
2397
+ swap(c, i++ , j-- );
2376
2398
}
2377
2399
}
2400
+
2401
+ private void swap(char [] c, int i, int j) {
2402
+ char t = c[i];
2403
+ c[i] = c[j];
2404
+ c[j] = t;
2405
+ }
2378
2406
```
2379
2407
2380
2408
# 58.2 左旋转字符串
2381
2409
2382
2410
## 题目描述
2383
2411
2412
+ [ NowCoder] ( https://www.nowcoder.com/practice/12d959b108cb42b1ab72cef4d36af5ec?tpId=13&tqId=11196&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking )
2413
+
2384
2414
对于一个给定的字符序列 S,请你把其循环左移 K 位后的序列输出。例如,字符序列 S=”abcXYZdef”, 要求输出循环左移 3 位后的结果,即“XYZdefabc”。
2385
2415
2386
2416
## 解题思路
2387
2417
2418
+ 将 "abcXYZdef" 旋转左移三位,可以先将 "abc" 和 "XYZdef" 分别旋转,得到 "cbafedZYX",然后再把整个字符串旋转得到 "XYZdefabc"。
2419
+
2388
2420
``` java
2389
2421
public String LeftRotateString(String str, int n) {
2390
- if ( str. length() == 0 ) return " " ;
2391
- char [] c = str. toCharArray();
2392
- reverse(c , 0 , n - 1 );
2393
- reverse(c , n, c . length - 1 );
2394
- reverse(c , 0 , c . length - 1 );
2395
- return new String (c );
2422
+ if (n >= str. length()) return str ;
2423
+ char [] chars = str. toCharArray();
2424
+ reverse(chars , 0 , n - 1 );
2425
+ reverse(chars , n, chars . length - 1 );
2426
+ reverse(chars , 0 , chars . length - 1 );
2427
+ return new String (chars );
2396
2428
}
2397
2429
2398
- private void reverse(char [] c, int i, int j) {
2399
- while (i < j) {
2400
- char t = c[i]; c[i] = c[j]; c[j] = t;
2401
- i++ ; j-- ;
2430
+ private void reverse(char [] chars, int i, int j) {
2431
+ while (i < j) {
2432
+ swap(chars, i++ , j-- );
2402
2433
}
2403
2434
}
2435
+
2436
+ private void swap(char [] chars, int i, int j) {
2437
+ char t = chars[i];
2438
+ chars[i] = chars[j];
2439
+ chars[j] = t;
2440
+ }
2404
2441
```
2405
2442
2406
2443
# 59. 滑动窗口的最大值
2407
2444
2408
2445
## 题目描述
2409
2446
2447
+ [ NowCoder] ( https://www.nowcoder.com/practice/1624bc35a45c42c0bc17d17fa0cba788?tpId=13&tqId=11217&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking )
2448
+
2410
2449
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组 {2, 3, 4, 2, 6, 2, 5, 1} 及滑动窗口的大小 3,那么一共存在 6 个滑动窗口,他们的最大值分别为 {4, 4, 6, 6, 6, 5}。
2411
2450
2412
2451
## 解题思路
2413
2452
2414
2453
``` java
2415
2454
public ArrayList<Integer > maxInWindows(int [] num, int size) {
2416
2455
ArrayList<Integer > ret = new ArrayList<> ();
2417
- if (size > num. length || size < 1 ) return ret;
2418
- // 构建最大堆,即堆顶元素是堆的最大值。
2419
2456
PriorityQueue<Integer > heap = new PriorityQueue<Integer > ((o1, o2) - > o2 - o1);
2457
+ if (size > num. length || size < 1 ) return ret;
2420
2458
for (int i = 0 ; i < size; i++ ) heap. add(num[i]);
2421
2459
ret. add(heap. peek());
2422
- for (int i = 1 ; i + size - 1 < num. length; i++ ) {
2460
+ for (int i = 1 , j = i + size - 1 ; j < num. length; i++ , j ++ ) {
2423
2461
heap. remove(num[i - 1 ]);
2424
- heap. add(num[i + size - 1 ]);
2462
+ heap. add(num[j ]);
2425
2463
ret. add(heap. peek());
2426
2464
}
2427
2465
return ret;
@@ -2432,35 +2470,39 @@ public ArrayList<Integer> maxInWindows(int[] num, int size) {
2432
2470
2433
2471
## 题目描述
2434
2472
2473
+ [ Lintcode] ( https://www.lintcode.com/en/problem/dices-sum/ )
2474
+
2435
2475
把 n 个骰子仍在地上,求点数和为 s 的概率。
2436
2476
2437
2477
## 解题思路
2438
2478
2439
2479
### 动态规划解法
2440
2480
2481
+ 使用一个二维数组 dp 存储点数出现的次数,其中 dp[ i] [ j ] 表示前 i 个骰子产生点数 j 的次数。
2482
+
2441
2483
空间复杂度:O(N<sup >2</sup >)
2442
2484
2443
2485
``` java
2444
- private static int face = 6 ;
2445
-
2446
- public double countProbability(int n, int s) {
2447
- if (n < 1 || s < n) return 0.0 ;
2448
- int pointNum = face * n;
2449
- int [][] dp = new int [n][pointNum];
2450
- for (int i = 0 ; i < face; i++ ) {
2451
- dp[0 ][i] = 1 ;
2486
+ public List<Map .Entry<Integer , Double > > dicesSum(int n) {
2487
+ final int face = 6 ;
2488
+ final int pointNum = face * n;
2489
+ long [][] dp = new long [n + 1 ][pointNum + 1 ];
2490
+ for (int i = 1 ; i <= face; i++ ) {
2491
+ dp[1 ][i] = 1 ;
2452
2492
}
2453
- for (int i = 1 ; i < n; i++ ) {
2454
- for (int j = i; j < pointNum; j++ ) { // 使用 i 个骰子最小点数为 i
2455
- for (int k = 1 ; k <= face; k++ ) {
2456
- if (j - k >= 0 ) {
2457
- dp[i][j] += dp[i - 1 ][j - k];
2458
- }
2493
+ for (int i = 2 ; i <= n; i++ ) {
2494
+ for (int j = i; j <= pointNum; j++ ) { // 使用 i 个骰子最小点数为 i
2495
+ for (int k = 1 ; k <= face && k <= j; k++ ) {
2496
+ dp[i][j] += dp[i - 1 ][j - k];
2459
2497
}
2460
2498
}
2461
2499
}
2462
- int totalNum = (int ) Math . pow(6 , n);
2463
- return (double ) dp[n - 1 ][s - 1 ] / totalNum;
2500
+ final double totalNum = Math . pow(6 , n);
2501
+ List<Map .Entry<Integer , Double > > ret = new ArrayList<> ();
2502
+ for (int i = n; i <= pointNum; i++ ) {
2503
+ ret. add(new AbstractMap .SimpleEntry<> (i, dp[n][i] / totalNum));
2504
+ }
2505
+ return ret;
2464
2506
}
2465
2507
```
2466
2508
@@ -2469,28 +2511,30 @@ public double countProbability(int n, int s) {
2469
2511
空间复杂度:O(N)
2470
2512
2471
2513
``` java
2472
- private static int face = 6 ;
2473
-
2474
- public double countProbability(int n, int s) {
2475
- if (n < 1 || s < n) return 0.0 ;
2476
- int pointNum = face * n;
2477
- int [][] dp = new int [2 ][pointNum];
2478
- for (int i = 0 ; i < face; i++ ) {
2514
+ public List<Map .Entry<Integer , Double > > dicesSum(int n) {
2515
+ final int face = 6 ;
2516
+ final int pointNum = face * n;
2517
+ long [][] dp = new long [2 ][pointNum + 1 ];
2518
+ for (int i = 1 ; i <= face; i++ ) {
2479
2519
dp[0 ][i] = 1 ;
2480
2520
}
2481
2521
int flag = 1 ;
2482
- for (int i = 1 ; i < n; i++ ) {
2483
- for (int j = i; j < pointNum; j++ ) { // 使用 i 个骰子最小点数为 i
2484
- for (int k = 1 ; k <= face; k++ ) {
2485
- if (j - k >= 0 ) {
2486
- dp[flag][j] += dp[1 - flag][j - k];
2487
- }
2522
+ for (int i = 2 ; i <= n; i++ , flag = 1 - flag) {
2523
+ for (int j = 0 ; j <= pointNum; j++ ) {
2524
+ dp[flag][j] = 0 ; // 旋转数组清零
2525
+ }
2526
+ for (int j = i; j <= pointNum; j++ ) { // 使用 i 个骰子最小点数为 i
2527
+ for (int k = 1 ; k <= face && k <= j; k++ ) {
2528
+ dp[flag][j] += dp[1 - flag][j - k];
2488
2529
}
2489
2530
}
2490
- flag = 1 - flag;
2491
2531
}
2492
- int totalNum = (int ) Math . pow(6 , n);
2493
- return (double ) dp[flag][s - 1 ] / totalNum;
2532
+ final double totalNum = Math . pow(6 , n);
2533
+ List<Map .Entry<Integer , Double > > ret = new ArrayList<> ();
2534
+ for (int i = n; i <= pointNum; i++ ) {
2535
+ ret. add(new AbstractMap .SimpleEntry<> (i, dp[1 - flag][i] / totalNum));
2536
+ }
2537
+ return ret;
2494
2538
}
2495
2539
```
2496
2540
0 commit comments