校招中遇到的常见算法题总结(持续更新)

主要是相关的题型,原题较少

1、最长公共子序列(leetcode-1143

经典的二维动态规划问题之一

  • 动态规划难点在于如何定义dp,此处为寻找两个字符序列的最长公共子序列,即从头到尾中去最长。故可将dp[i][j]定义为字符串s1,s2的长度为i和j的前缀的最长子序列长度

即dp[i][j]表示s1.substring(0,i)和s1.substring(0,j)的最长子序列长度

  • 随后是边界问题
    显然,当i=0时,dp[0][j]都为0,同理j=0时,dp[i][j]=0,dp[0][0]=0

  • 紧接着就是一般性分析(找i,j逐渐增大时的递推式,显然和最后一个字符相关)

    • 当s1.charAt(i)==s2.charAt(j)时,则dp[i][j]等于dp[i-1][j-1]+1

      eg: s1: acg; s2:dag dp[3][3]=dp[2][2]+1=1+1=2

    • 当s1.chas1.charAt(i)!=s2.charAt(j)时,dp[i][j-1],dp[i-1][j]取其中的较大值

      eg: s1: acf; s2:afgd dp[3][3]=Math.max(dp[2][3],dp[3][2])=max(1,2)=2

总结

  • dp[i][j]=dp[i-1][j-1]+1 when s1.charAt(i)==s2.charAt(j);
  • dp[i][j]=Math.max(dp[i][j-1],dp[i-1][j]) when s1.charAt(i)!=s2.charAt(j);

Java代码如下:

public int longestCommonSubsequence(String s1, String s2) {
    int n1=s1.length(),
        n2=s2.length();
    int[][] dp=new int[n1+1][n2+1];
    int result=0;
    dp[0][0]=0;//边界值
    for(int i=1;i<=n1;i++){//边界值
        dp[i][0]=0;
    }
    for(int j=1;j<=n2;j++){//边界值
        dp[0][j]=0;
    }
    for(int k1=1;k1<=n1;k1++){//一般性分析
        char c=s1.charAt(k1-1);
        for(int k2=1;k2<=n2;k2++){
            if(s2.charAt(k2-1)==c){//最后一个字符相等时
                dp[k1][k2]=dp[k1-1][k2-1]+1;
            }else{//最后一个字符不等时
                dp[k1][k2]=Math.max(dp[k1][k2-1],dp[k1-1][k2]);
            }
        }
    }
    return dp[n1][n2];
}

2、手撕快速排序(基准值随机选取)

class Solution {
public int[] sortArray(int[] nums) {
    quickSort(nums,0,nums.length-1);
    return nums;
}
private static void quickSort(int[] nums,int l,int r){
    if(l<r){
        int privot=partion(nums,l,r);
        quickSort(nums,l,privot-1);
        quickSort(nums,privot+1,r);
    }
}
private static int partion(int[] nums,int l,int r){
    int i=new Random().nextInt(r-l+1)+l;//此处随机选择快排基准值的位置
    swap(nums,r,i);//将其移动到末尾
    return partionCount(nums,l,r);
}
private static int partionCount(int[] nums,int l,int r){
    int privot=nums[r];
    int i=l-1;
    for(int j=l;j<r;j++){
        if(nums[j]<=privot){//交换小于基准和大于基准的两个数
            i++;
            swap(nums,i,j);
        }
    }
    swap(nums,i+1,r);
    return i+1;
}
private static void swap(int[] nums,int i,int j){
    int tmp=nums[i];
    nums[i]=nums[j];
    nums[j]=tmp;
}
}