本文首发于稀土掘金。该平台的作者 逐光而行 也是本人。
入坑力扣周赛以来,从一开始的0题选手到现在慢慢已经能做出2题左右了,能很明显地感觉到最近几场的周赛难度有所降低(而且从数据上看,之前做出两题能排到2000多,最近只能到4000多),打比赛就是这样,你追我赶,逆水行舟,不进则退。目前我做三四题还处于赛时一脸懵,赛后马后炮的状态,希望通过不断总结与反思,能慢慢跨上新台阶。
————写在最前面
Q1:枚举因子
送分题:
class Solution {
public int commonFactors(int a, int b) {
int cnt=0;
int min=(a>b)?b:a;
for(int i=1;i<=min;i++){
if(a%i==0&&b%i==0) cnt++;
}
return cnt;
}
}
Q2:沙漏的最大总和
我的方法有点笨,没有技巧,只剩感情。
对于矩阵中的每个元素,如果它往下往右扩展3个单位的范围没有越界,就去计算该范围除了腰间两个数以外的总数和。
class Solution {
public int maxSum(int[][] grid) {
int m=grid.length,n=grid[0].length;
int res=0;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(i+3<=m&&j+3<=n){
res=Math.max(res,getSum(grid,i,j));
}
}
}
return res;
}
public int getSum(int [][] grid,int i,int j){
int sum=0;
int a=0;
while(a<3){
int b=0,tmp=j;
while(b<3){
sum+=(a==1&&b!=1)?0:grid[i][tmp];
b++;
tmp++;
}
a++;
i++;
}
return sum;
}
}
Q3:最小XOR
这个我当时想到了是从高位到低位补1,如果1还没用完,就反过来从低位到高位继续补。不过比赛中途代码差了点意思,用了转字符串之类的方法。赛后一看 @灵茶山艾府 大佬的解法,醍醐灌顶,原来可以直接原地位运算。
class Solution {
public int minimizeXor(int num1, int num2) {
int bitcnta=Integer.bitCount(num1);
int bitcntb=Integer.bitCount(num2);
int bitlena=0;
int tmp=num1;
while(tmp>0){
tmp/=2;
bitlena++;
}
int x=0;
if(bitcntb>=bitlena) return (1<<bitcntb)-1;
//总体思路:从高位往低位用1,用不完的再从低位往高位补
while(bitcntb<bitcnta){
num1&=num1-1;
bitcntb+=1;
}
x=~num1;
while(bitcnta<bitcntb){
num1|=x&-x;
x&=x-1;
bitcntb-=1;
}
return num1;
}
}
Q4:对字母串可执行的最大删除数
据力扣大佬们说这是经典dp问题。(虽然我当时是没有看出来的,但是看了大佬们的解法觉得很有道理。)
lcp数组和dp数组都是逆着用的,他们似乎管这叫“记忆化搜索”(不知道有没有记错)
lcp数组记录的是字符串的最长公共前缀(longest common prefix),dp记录的是删除后缀后所需要的最大操作数。
如果当前两个字符相等,即lcp前后两个状态相差1;
第二个双for循环中,if的作用是判断两个子串是否相等,是,就取最大值。
class Solution {
public int deleteString(String s) {
int n=s.length();
int [][] lcp=new int [n+1][n+1];
int [] dp=new int [n];
for(int i=n-1;i>=0;i--){
for(int j=n-1;j>=0;j--){
if(s.charAt(i)==s.charAt(j)){
lcp[i][j]=lcp[i+1][j+1]+1;
}
}
}
for(int i=n-1;i>=0;i--){
for(int j=1;i+j*2<=n;j++){
if(lcp[i][i+j]>=j){
dp[i]=Math.max(dp[i],dp[i+j]);
}
}
dp[i]++;
}
return dp[0];
}
}