0%

2022-0825

[toc]

第一题双指针#

剑指 Offer II 018. 有效的回文 - 力扣(LeetCode)

1661443175105

双指针,处理字符串比较麻烦

反正都是O(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
class Solution {
public boolean isPalindrome(String s) {
int left = 0, right = s.length()-1;
s = s.toUpperCase();
// todo:Character.isLetterOrDigit(s.charAt(right))可以代替
while(left <= right && left <s.length() && !Character.isDigit(s.charAt(left)) && !Character.isAlphabetic(s.charAt(left))) {
left++;
}

while(left <= right && right >=0 && !Character.isDigit(s.charAt(right)) && !Character.isAlphabetic(s.charAt(right))) {
right--;
}
while(left <right) {

if (s.charAt(left) != s.charAt(right)) {
return false;
}
left++;
right--;
while(left <= right && left <s.length() && !Character.isDigit(s.charAt(left)) && !Character.isAlphabetic(s.charAt(left))) {
left++;
}

while(left <= right && right >=0 && !Character.isDigit(s.charAt(right)) && !Character.isAlphabetic(s.charAt(right))) {
right--;
}
}
return true;
}
}

字符串翻转做法:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public boolean isPalindrome(String s) {
int left = 0, right = s.length()-1;
s = s.toUpperCase();
StringBuilder sb =new StringBuilder();
for (char c : s.toCharArray()) {
if (Character.isLetterOrDigit(c)) {
sb.append(c);
}
}
return sb.toString().equals(sb.reverse().toString());
}
}

注意Character.isLetterOrDigit©就是判断是否是字母或者数字的意思

注意sb.reverse()会改变自身

第二题博弈论,记忆化搜索#

1140. 石子游戏 II - 力扣(LeetCode)

1661443467395

这种博弈论问题,请直接dfs+记忆化搜索好吧,别纠结动态规划了

而且直接考虑根据当前人的不同,选取最大或者最小值,不要考虑那个简化正负的那种策略。

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
class Solution {
Integer[][][] dp;

public int stoneGameII(int[] piles) {
dp = new Integer[2][piles.length][101];
return dfs(0, 1, piles, true);
}

// 返回alice能拿到的石头
int dfs(int index, int m, int[] piles, boolean isAlice) {

if (index == piles.length) {
return 0;
}
if (dp[isAlice ? 0 : 1][index][m] != null) {
return dp[isAlice ? 0 : 1][index][m];
}

int needDfsRes = (isAlice ? Integer.MIN_VALUE :
Integer.MAX_VALUE);
int sum = 0;
for (int i = index;i<index + 2*m && i < piles.length;i++) {
int dfsRes = dfs(i+1, Math.max(i - index + 1, m),
piles, !isAlice);
if (isAlice) {
sum += piles[i];
needDfsRes = Math.max(needDfsRes, sum + dfsRes);
} else {
needDfsRes = Math.min(needDfsRes, dfsRes);
}
}
dp[isAlice ? 0 : 1][index][m] = needDfsRes;
return needDfsRes;
}
}

第三题二分查找#

540. 有序数组中的单一元素 - 力扣(LeetCode)

1661443586836

要求O(logn),显然不能用异或的那个方法了

既然是有序的,说明相同的2个数字一定是连在一起的

那么在目标左边的连体数字,一定是偶数索引开头

目标右边的连体数字,一定是奇数索引开头

搞定

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
class Solution {
public int singleNonDuplicate(int[] nums) {
int left = 0, right = nums.length;
while(left < right) {
int mid = left + (right - left)/2;
int num1 = nums[mid];
int index1 = -1;
if (mid-1 >=0 && nums[mid-1] == num1) {
index1 = mid-1;
} else if (mid+1<nums.length && nums[mid+1] == num1) {
index1 = mid;
}
if (index1 == -1) {
return num1;
}
// 相同2个数的第一个数的索引是偶数,说明那个要求的数字在右边
// 如果第一个索引是奇书,说明前面被某个单个数字插入过,改变了索引情况
if (index1 %2 == 0) {
left = mid+1;
} else {
right = mid;
}
}
return -1;
}
}