20201016:Leikou Week 210ウィークリーコンテスト質問ソリューション(パート2)

Leikou Week 210ウィークリーコンテストの質問(パート2)

トピック

    1. 回文を取得するために2つの文字列を分割します
      ここに画像の説明を挿入
    1. サブツリー内の都市間の最大距離を数えます
      ここに画像の説明を挿入

アイデアとアルゴリズム

  1. 3番目の質問の主な論理は滑らかである必要があります。セグメンテーションのインデックスは同じであることに注意してください。回文を判断する論理は、aの前半とbの後半がまったく同じである場合、回文にスプライスすることができます、そうでなければ到達しません。ポイントの分割点とそれと対称的な分割点の間の部分は、要件を満たすために回文自体です。コードは以下のように表示されます
  2. 4番目の質問は、大物@ zhangyixing1007からのコード実装に投稿されています。記述が詳細すぎて、状態の圧縮が学習されています。

コード

    1. 回文を取得するために2つの文字列を分割します
class Solution {
    
    
    public boolean checkPalindromeFormation(String a, String b) {
    
    
        return helper(a,b) || helper(b,a);    
    }

    private boolean helper(String a,String b){
    
    
        char[] A = a.toCharArray();
        char[] B = b.toCharArray();
        int len = A.length;
        // a正序,b逆序遍历,判断在mid之前是否为全相等,
        int index = 0;
        int half = len >> 1;
        while(index <= half){
    
    
            if(A[index] == B[len - 1 - index]){
    
    
                index++;
            } else {
    
    
                break;
            }
        }
       
        // 如果过半相同,意味着我们可以在half处分割开然后拼接a的前半部和b的后半部即可
        if (index >= half) {
    
    
            return true;
        }

        // 如果不幸,half不过半,那么也就是说,我们目前只有a的[0,index]和b的[len-1-index,len]是回文的,但是不可能分割得到,那么
        // 也就是说从[index, len-1-index]这一段必须自身就是回文串,那么分割后他才可能与前面本身就是回文串的pre或者suf拼接完成。
        if (isPalindrome(a,index,len- 1 - index) || isPalindrome(b,index,len - 1 - index)) {
    
    
            return true;
        }
        return false;
        
    }

    // 判断是否为回文串,left和right为索引值
    private boolean isPalindrome (String s,int left,int right) {
    
    
        String tmp = s.substring(left,right+1);
        char[] cTmp = tmp.toCharArray();
        int len = cTmp.length;
        for (int i = 0; i < len/2; i++) {
    
    
            if (cTmp[i] != cTmp[len - 1 - i]) {
    
    
                return false;
            }
        }
        return true;
    }
}
    1. サブツリー内の都市間の最大距離を数えます
class Solution {
    
    
    public int[] countSubgraphsForEachDiameter(int n, int[][] edges) {
    
    
        int[][] dist=new int[n][n]; //存储两点之间的距离
        for(int i=0; i<n; i++){
    
    
            Arrays.fill(dist[i], Integer.MAX_VALUE);
            //之后要求最小值 所以初始化成最大整数
            //其实初始化成任何一个大于等于n的数字都可以
            dist[i][i]=0;//本身到本身显然为0
        }        
        int[] dp=new int[1<<(n)];
        //状态压缩存储 dp[j]表示子树j的最大距离
        //j表示成二进制,从右数第k位为1表示第k个节点在子集中否则不在
        for(int[] edge:edges){
    
    
            // 直接相连的两点之间距离显然为1
            dist[edge[0]-1][edge[1]-1]=1;
            dist[edge[1]-1][edge[0]-1]=1;
            // 直接相连的两点可以构成一棵子树 它们的最大距离为1
            dp[(1<<(edge[0]-1)) + (1<<(edge[1]-1))]=1;
        }
        // Floyed算法 求每两点之间的最短距离 请全文背诵
        for(int k=0; k<n; k++){
    
    
            for(int i=0; i<n; i++){
    
    
                for(int j=0; j<n; j++){
    
    
                    if(dist[i][k]!=Integer.MAX_VALUE && dist[k][j]!=Integer.MAX_VALUE){
    
    
                        dist[i][j]=Math.min(dist[i][j], dist[i][k]+dist[k][j]);
                    }
                }
            }
        }
        // 把对j的循环放在外面
        // 因为显然如果子树A是子树B的一部分 jA<jB
        // 所以要把数字小的j全部求好了再去求数字大的j
        for(int j=1; j<dp.length; j++){
    
    
            // 以下我们从子树 j 扩展到子树 j+(1<<i)
            // 即把节点i加入到子树j中
            // 如果本身j就无法构成一棵子树(如果j表示的节点不能相互连通)
            // 那么也就没有必要继续了 所以continue
            if(dp[j]==0) continue;
            for(int i=0; i<n; i++){
    
    
                // 如果节点i已经在子树j中 或者 j+(1<<i)已经被计算过了 就没必要算了
                // 为什么它可能会已经被计算过呢? 
                // 因为 111=101+10=11+100 添加点的顺序不同 但是能得出同样的一棵子树
                if(((1<<i)&j)!=0 || dp[j+(1<<i)]!=0) continue;
                // 检查 j 子树中是否有和 i 直接相连的点 
                // 这其实是相对于子树(而不是某个节点的)的bfs
                for(int k=0; k<n; k++){
    
    
                    if(((1<<k)&j)!=0 && dist[i][k]==1){
    
    
                        dp[j+(1<<i)]=dp[j];
                        break;
                    }
                }
                // 如果j 子树中没有和 i 直接相连的点
                // 那么也就无法添加这个节点i了
                if(dp[j+(1<<i)]==0) continue;
                // 把节点i添加进来 就要更新新子树的最大距离 dp[j+(1<<i)]
                // 更新的办法是 对于原子树的每一个节点和新节点求最大距离
                // 因为只产生了这些新距离 做增量计算就好
                for(int kk=0; kk<n; kk++){
    
    
                    if(((1<<kk)&j)!=0){
    
    
                        dp[j+(1<<i)]=Math.max(dp[j+(1<<i)], dist[i][kk]);
                    }
                }
            }
        }
        // 统计结果 由于下标从1开始 
        // ans[0]其实记录的是最大距离为1的子树有多少棵 统计时要-1
        int[] ans=new int[n-1];
        for(int j=0; j<dp.length; j++){
    
    
            if(dp[j]!=0) ans[dp[j]-1]++;
        }
        return ans;
    }
}

最後に書く

ラッシュ!

おすすめ

転載: blog.csdn.net/qq_36828395/article/details/109126234
おすすめ