LeetCode 精选 41-55 until 10-10
41. 缺失的第一个正数
哈希的本质
🤔哈希其实并没有直接完成键到值的映射,实际上是完成了键->索引
的映射
至于索引(循秩访问)当中的内容
这个元素曾经出现过
if(nums[i - 1] == FLAG)
这个题目有特殊的限制:[1,N+1]固定区间出现答案,因此,不需要额外空间
如何实现可见区间之内的计数?
-
合法区间之内,在指定位置映射上一个标记
-
如果该位置存在一个没有被处理的数字
-
那么进行如下操作
// 注意防止死循环 // nums[x - 1] != x 即未做标记 while(valid(nums[i]) && nums[i] != nums[nums[i] - 1])swap(nums[i],nums[nums[i] - 1]);
-
-
合法区间之外,不做标记
class Solution {
public int firstMissingPositive(int[] nums) {
int len = nums.length;
for(int i = 0;i<len;i++){
// for each element
while(nums[i]>0 && nums[i] <=len && nums[i] != nums[nums[i] - 1])swap(nums,i,nums[i] - 1);
}
for(int i = 0;i<len;i++){
if(nums[i] != i + 1)return i + 1;
}
return len + 1;
}
void swap(int[] nums,int i,int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
通过多重属性解决覆盖 / 后效性问题
42. 接雨水
动态规划 ≈黎曼积分
❗注意:L[0] = height[0] 报错💣
height[0]也不一定存在
class Solution {
int[] L;
int[] R;
public int trap(int[] height) {
if(height.length == 0)return 0;
L = new int[height.length];
R = new int[height.length];
L[0] = height[0];
for(int i = 1;i<height.length;i++){
L[i] = Math.max(height[i],L[i-1]);
}
R[height.length - 1] = height[height.length - 1];
for(int i = height.length - 2;i>=0;i--){
R[i] = Math.max(height[i],R[i+1]);
}
int ans = 0;
for(int i = 0;i<height.length;i++){
// assess the final condition
// there is a column of water supported by the brick beneath
ans += Math.min(L[i],R[i]) - height[i];
}
return ans;
}
}
单调栈
这个方法感觉普遍性不强
class Solution {
Stack<Integer> s;
public int trap(int[] height) {
s = new Stack<Integer>();
int ans = 0;
int cur = 0;
while(cur < height.length){
while(!s.empty() && height[s.peek()] < height[cur]){
int i = s.pop();
if(s.empty())break;
int d = cur - s.peek() - 1;
int h = Math.min(height[s.peek()],height[cur]) - height[i];
ans += h * d;
}
s.push(cur++);
}
return ans;
}
}
44. 通配符匹配
输入:
"ho" "**ho"
输出:
false
预期结果:
true
# h o
# * * h o
考察必要条件:如果需要一个true的结果,必须保证dp[0][2] = true
dp[0][2] = dp[0][1] = dp[0][0] = true;
class Solution {
boolean [][] dp;
public boolean isMatch(String s, String p) {
// null
if(s.length()== 0 && p.length()==0)return true;
if(s.length()!= 0 && p.length()==0)return false;
int len1 = s.length();
int len2 = p.length();
// bounding flags
dp = new boolean[len1+10][len2+10];
dp[0][0] = true;
if(p.charAt(0) == '*'){
for(int i = 0;i<=len1;i++){
dp[i][1] = true;
}
}
for(int i = 0;i<=len1;i++){
for(int j = 1;j<=len2;j++){
if(p.charAt(j-1) == '?'){
if(i>=1)dp[i][j] = dp[i-1][j-1];
}else if(p.charAt(j-1) == '*'){
// neglect or use it as '?'
dp[i][j] = dp[i][j-1];
if(i>=1)dp[i][j] |= dp[i-1][j-1] | dp[i-1][j];
}else{
if(i>=1 && p.charAt(j-1) == s.charAt(i-1)){
dp[i][j] = dp[i-1][j-1];
}else{
dp[i][j] = false;
}
}
}
}
return dp[len1][len2];
}
}
代码简化
if(p.charAt(0) == '*'){
for(int i = 0;i<=len1;i++){
dp[i][1] = true;
}
}
下面的这段代码很好地实现了对连续*号
的标记
for & break
for (int i = 1; i <= n; ++i) {
if (p.charAt(i - 1) == '*') {
dp[0][i] = true;
} else {
break;
}
}
else if(p.charAt(j-1) == '*'){
// neglect or use it as '?'
dp[i][j] = dp[i][j-1];
if(i>=1)dp[i][j] |= dp[i-1][j-1] | dp[i-1][j];
}
这段代码实际上和 dp[i][j] = dp[i-1][j] | dp[i][j-1];
等价
dp[i-1][j-1]
(匹配一个并且跳过) = dp[i][j-1]
& dp[i-1][j]
46. 全排列
回溯法
class Solution {
List<List<Integer>> ret;
List<Integer> out;
int n;
public List<List<Integer>> permute(int[] nums) {
ret = new ArrayList<List<Integer>>();
out = new ArrayList<Integer>();
n = nums.length;
for(int i : nums){
out.add(i);
}
bp(0);
return ret;
}
public void bp(int cur){
if(cur == n){
ret.add(new ArrayList<Integer>(out));
return;
}else{
for(int i = cur;i<n;i++){
// 其实 i = cur没有用
Collections.swap(out,i,cur);
// 但是需要保证 bp(cur + 1)可以进入
bp(cur+1);
Collections.swap(out,i,cur);
}
}
}
}
48. 旋转图像
遍历每一个元素,需要开辟O(N^2)的辅助空间
群论——变换的连续作用
对角线反转 + 对于垂直中线的反射 = 顺指针旋转90°
工程思想——单变量辅助,就地反转
You’re just one step away from the answer:
Give an Example!
🔑BUFFER
考虑数组删除元素后的移动操作
class Solution {
public void rotate(int[][] matrix) {
int n = matrix.length;
// layer
for(int l = 0;l<n/2;l++){
// no.
for(int i = l;i<n-l-1;i++){
int r = l;
int c = i;
int temp = matrix[r][c];
// r,c
// c,n-1-r
// n-1-r,n-1-c
// n-1-c,r
// inv. order
matrix[r][c] = matrix[n-1-c][r];
matrix[n-1-c][r] = matrix[n-1-r][n-1-c];
matrix[n-1-r][n-1-c] = matrix[c][n-1-r];
matrix[c][n-1-r] = temp;
}
}
}
}
49. 字母异位词分组
一遍过!
class Solution {
Map<Map<Character,Integer>,List<String>> map;
void gen(String word){
Map<Character,Integer> count = new HashMap<Character,Integer>();
for(int i = 0;i<word.length();i++){
char c = word.charAt(i);
count.put(c,count.getOrDefault(c,0)+1);
}
if(!map.containsKey(count)){
List<String> list = new ArrayList<String>();
list.add(word);
map.put(count,list);
}else{
map.get(count).add(word);
}
}
public List<List<String>> groupAnagrams(String[] strs) {
map = new HashMap<Map<Character,Integer>,List<String>>();
for(String s : strs){
gen(s);
}
List<List<String>> ans = new ArrayList<List<String>>();
for(List<String> list: map.values()){
ans.add(list);
}
return ans;
}
}
排序字符串:同素异形体😂的充要条件,可以直接作为键
53. 最大子序和
这个自己写还真是写不出来……
PS:举例子的时候一定要举得全面一点,看似正确的方法其实不一定对
软件测试的重要性 hhh
class Solution {
public int maxSubArray(int[] nums) {
int[] dp = new int[nums.length];
int ans = Integer.MIN_VALUE,sum = 0;
for(int i = 0;i<nums.length;i++){
// max contiguous subarray with nums[i-1] as tail
sum = Math.max(sum + nums[i],nums[i]);
// then you choose whether to accept it
ans = Math.max(ans,sum);
}
return ans;
}
}
分治——线段树思想
50. Pow(x, n)
💃 AC!
class Solution {
public double myPow(double x, int n) {
double ans = 1.0;
if(n == Integer.MIN_VALUE){
n++;
ans = x;
}
boolean neg = n<0;
if(n<0)n = -n;
double base = x;
while(n!=0){
if((n&1) == 1){
ans *= base;
}
base *= base;
n >>= 1;
}
return neg?1/ans:ans;
}
}
54. Spiral Matrix
动态Bound
class Solution {
int m,n;
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> ans = new ArrayList<Integer>();
int m = matrix.length;
if(m == 0)return ans;
int n = matrix[0].length;
int tar = m*n;
int l = 0,r = n - 1,u = 0,b = m - 1;
int count = 0;
while(count < tar){
for(int i = l;i<=r;i++){
ans.add(matrix[u][i]);
count++;
}
u++;
if(count >= tar)break;
for(int i = u;i<=b;i++){
ans.add(matrix[i][r]);
count++;
}
r--;
if(count >= tar)break;
for(int i = r;i>=l;i--){
ans.add(matrix[b][i]);
count++;
}
b--;
if(count >= tar)break;
for(int i = b;i>=u;i--){
ans.add(matrix[i][l]);
count++;
}
l++;
if(count >= tar)break;
}
return ans;
}
}
55. Jump Game
做一个小证明
nums[len - 1]
可达等效于
bound <= len-1
-
必要性显然,既bound的含义
-
充分性
如果可达nums[len - 1],必然有nums[k]可达,并且nums[k] + k >= len - 1;
??这话咋说?
就这?😂
class Solution {
public boolean canJump(int[] nums) {
int b = 0;
for(int i = 0;i<nums.length;i++) b = i<=b?Math.max(b,i+nums[i]):b;
return b >= (nums.length - 1);
}
}
本文来自博客园,作者:ZXYFrank,转载请注明原文链接:https://www.cnblogs.com/zxyfrank/p/13938826.html