• LeedCode第 244 场周赛(二)


    5776. 判断矩阵经轮转后是否一致

    题目链接:https://leetcode-cn.com/problems/determine-whether-matrix-can-be-obtained-by-rotation/

    给你两个大小为 n x n 的二进制矩阵 mat 和 target 。现 以 90 度顺时针轮转 矩阵 mat 中的元素 若干次 ,如果能够使 mat 与 target 一致,返回 true ;否则,返回 false 。

     题目思路:

    主要给出转换过程中每个点的横纵坐标的变化表示,比如,设置矩阵中任意一点A的坐标是(i ,j),则顺时针旋转90度后的坐标是(j , n-1-i),继续顺时针旋转90度后的坐标是(n-1-i.n-1-j),接着再顺时针选择90度后的坐标是(n-1-j , i),最后顺时针旋转90度后,回到起点(i ,j)。

    C++代码:

     1 class Solution {
     2 public:
     3     bool findRotation(vector<vector<int>>& mat, vector<vector<int>>& target) {
     4         int n = mat.size();
     5         int m = target.size();
     6         int sum=0;
     7         int sum1=0;
     8         int sum2=0;
     9         int sum3=0;
    10         if(m==n)
    11         {
    12             for(int i=0; i<n ;i++)
    13             {
    14                 for(int j=0 ;j<n; j++)
    15                 {
    16                     if(mat[i][j]==target[i][j])
    17                     {   
    18                        // printf("%d %d
    ",i,j);
    19                         sum++;
    20                     }
    21                 }
    22             }
    23             
    24           for(int i=0; i<n ;i++)
    25             {
    26                 for(int j=0 ;j<n; j++)
    27                 {
    28                     if(mat[i][j]==target[j][n-1-i])
    29                     {   
    30                        // printf("%d %d
    ",i,j);
    31                         sum1++;
    32                     }
    33                 }
    34             }
    35             
    36             for(int i=0; i<n ;i++)
    37             {
    38                 for(int j=0 ;j<n; j++)
    39                 {
    40                     if(mat[i][j]==target[n-1-i][n-1-j])
    41                     {   
    42                        // printf("%d %d
    ",i,j);
    43                         sum2++;
    44                     }
    45                 }
    46             }
    47             
    48              for(int i=0; i<n ;i++)
    49             {
    50                 for(int j=0 ;j<n; j++)
    51                 {
    52                     if(mat[i][j]==target[n-1-j][i])
    53                     {   
    54                        // printf("%d %d
    ",i,j);
    55                         sum3++;
    56                     }
    57                 }
    58             }
    59      
    60             //if(sum2==sum3)
    61            // printf("sxiangtong %d %d
    ",sum2,sum3);
    62             int ans=n*n;
    63           //  printf("sum : %d ans: %d
    ",sum,ans);
    64             if((sum==ans) || (sum1==ans) || (sum2==ans) || (sum3==ans))
    65             {
    66                return true;
    67             }
    68             else
    69             {
    70               return false;
    71             }
    72         }
    73            
    74         else 
    75             return false;
    76     }
    77 };

     

    5777. 使数组元素相等的减少操作次数

    题目链接:https://leetcode-cn.com/problems/reduction-operations-to-make-the-array-elements-equal/

    给你一个整数数组 nums ,你的目标是令 nums 中的所有元素相等。完成一次减少操作需要遵照下面的几个步骤:

    找出 nums 中的 最大 值。记这个值为 largest 并取其下标 i (下标从 0 开始计数)。如果有多个元素都是最大值,则取最小的 i 。
    找出 nums 中的 下一个最大 值,这个值 严格小于 largest ,记为 nextLargest 。
    将 nums[i] 减少到 nextLargest 。
    返回使 nums 中的所有元素相等的操作次数。

     解题思路:

    先sort快排,然后采用前缀的思想,也可以理解为后一个数值和相邻的前一个数值有关,并把操作的次数记录下来。

    C++代码:

     1 class Solution {
     2 public:
     3     int reductionOperations(vector<int>& nums) {
     4         int n=nums.size();
     5         int ans=0;
     6         int sum[50005];
     7         memset(sum, 0, sizeof(sum));
     8         sort(nums.begin(),nums.end());
     9         for(int i=0;i<n-1;i++)
    10         {
    11             if(nums[i+1]!=nums[i])
    12             {
    13                 sum[i+1]=sum[i]+1;
    14             }
    15             else
    16             {
    17                 sum[i+1]=sum[i];
    18             }
    19         }
    20         for(int i=0 ; i<n ; i++)
    21         {
    22             ans = ans + sum[i];
    23         }
    24         return ans;
    25     }
    26 };

    5778. 使二进制字符串字符交替的最少反转次数

    题目链接:https://leetcode-cn.com/problems/minimum-number-of-flips-to-make-the-binary-string-alternating/

    给你一个二进制字符串 s 。你可以按任意顺序执行以下两种操作任意次:

    类型 1 :删除 字符串 s 的第一个字符并将它 添加 到字符串结尾。
    类型 2 :选择 字符串 s 中任意一个字符并将该字符 反转 ,也就是如果值为 '0' ,则反转得到 '1' ,反之亦然。
    请你返回使 s 变成 交替 字符串的前提下, 类型 2 的 最少 操作次数 。

    我们称一个字符串是 交替 的,需要满足任意相邻字符都不同。

    比方说,字符串 "010" 和 "1010" 都是交替的,但是字符串 "0100" 不是。

     解题思路1:

    滑动窗口的方法。

    对字符串 s 变成2倍的s。

    然后我们用0110交替创建两个相同长度的不同字符串例如:s =11100

      • s = 1110011100
      • s1 = 1010101010
      • s2= 0101010101
    • 最后,使用滑动窗口(大小 n)将 s 与 s1 和 s2 进行比较。
    • 为什么我们可以将 s 加倍来完成第一个操作,让我们看一下相同的示例 s = 11100:`
      • 双 s: 1110011100
      • 大小为n的窗口: |11100|11100 ==> 1|11001|1100 ==> 11|10011|100 以此类推,当我们移动滑动窗口一步时,同样从头开始追加1个元素。

    参考链接:https://leetcode.com/problems/minimum-number-of-flips-to-make-the-binary-string-alternating/discuss/1253874/C++-Solution-sliding-window.-O(N)

    C++代码:

     1 class Solution {
     2 public:
     3     int minFlips(string s) {
     4         int n = s.size();
     5         s += s;
     6         string s1, s2;
     7         
     8         for(int i = 0; i < s.size(); i++) {
     9             s1 += i % 2 ? '0' : '1';
    10             s2 += i % 2 ? '1' : '0';
    11         }
    12         int ans1 = 0, ans2 = 0, ans = INT_MAX;
    13         for(int i = 0; i < s.size(); i++) {
    14             if(s1[i] != s[i]) ++ans1;
    15             if(s2[i] != s[i]) ++ans2;
    16             if(i >= n) { //the most left element is outside of sliding window, we need to subtract the ans if we did `flip` before.
    17                 if(s1[i - n] != s[i - n]) --ans1;
    18                 if(s2[i - n] != s[i - n]) --ans2;
    19             }
    20             if(i >= n - 1)
    21                 ans = min({ans1, ans2, ans});
    22         }
    23         return ans;
    24     }
    25 };

    解题思路2:

    分析+前缀和+后缀和

    提示 1
    我们可以将所有类型 2的操作安排在类型 1 的操作之前。
    提示 1 解释
    由于类型 2 的操作是反转任意一个字符,而类型 1 的操作只会改变字符的相对顺序,不会改变字符的值。因此如果我们想要修改某个字符,随时都可以修改。这样我们就可以把所有类型 2 的操作安排到最前面。
    提示 2
    设字符串 ss 的长度为 n。

    如果 n 是偶数,那么在所有类型 2 的操作完成后,s 已经是一个交替字符串了。

    提示 2 解释

    当 n 是偶数时,交替字符串只可能为 010101⋯01 或者101010⋯10 的形式。对这两个字符串进行类型 2 的操作,只会在它们之间相互转换。

    类型 2 的操作是可逆的,这说明交替字符串只可能由交替字符串通过类型 2 的操作得来。因此,在所有类型 2 的操作完成后,s 必须是一个交替字符串。

    提示 3

    如果 n 是奇数,那么交替字符串为 0100101⋯010 或者 1011010⋯101 的形式。

    我们首先考虑 0100101⋯010,如果在所有类型 2 的操作完成后,s 可以通过类型 2 的操作得到该字符串,那么:

    要么 s 就是 0100101⋯010;

    要么 s 是  0101⋯010∣01⋯01 的形式,或者是  01010⋯10∣01⋯010 的形式。这里我们用竖线 | 标注了类型 2 的操作,在 | 左侧的字符通过类型 2 的操作被移动到字符串的末尾,最终可以得到 0100101⋯010。

    因此,s 要么是一个交替字符串(即  0100101⋯010),要么由两个交替字符串拼接而成,其中左侧的交替字符串以 0 结尾,右侧的交替字符串以 0 开头。

    同理,如果我们考虑  1011010⋯101,那么 s 要么就是 1011010⋯101,要么由两个交替字符串拼接而成,其中左侧的交替字符串以 1 结尾,右侧的交替字符串以 1 开头。


    我们用pre[i][j] 表示对于字符串的前缀 s[0..i]s[0..i],如果我们希望通过类型 2 的操作修改成「以 j 结尾的交替字符串」,那么最少需要的操作次数。这里 j 的取值为 0 或 1。根据定义,有递推式:
    pre[i][0]=pre[i−1][1]+I(s[i],1)
    pre[i][1]=pre[i−1][0]+I(s[i],0)


    其中 I(x,y) 为示性函数,如果 x=y,那么函数值为 1,否则为 0。例如 I(s[i],1) 就表示:如果s[i] 为 1,那么我们需要通过类型 2 的操作将其修改为 0,否则无需操作。

    同理,我们用suf[i][j] 表示对于字符串的后缀 s[0..i]s[0..i],如果我们希望通过类型 2 的操作修改成「以 j 开头的交替字符串」,那么最少需要的操作次数。这里 j 的取值为 0 或 1,同样有递推式:
    suf[i][0]=suf[i+1][1]+I(s[i],1)
    suf[i][1]=suf[i+1][0]+I(s[i],0)

    在求解完数组 pre 和suf 后:

    答案可以为 pre[n−1][0] 或者 pre[n−1][1],对应着将 s 本身变为一个交替字符串;

    如果 n 是奇数,那么答案还可以为 pre[i][0]+suf[i+1][0] 以及pre[i][1]+suf[i+1][1],对应着将 s 变为两个交替字符串的拼接。

    所有可供选择的答案中的最小值即为类型 2 的操作的最少次数。

    细节:如果 n 是偶数,我们无需求出 suf 。

    参考链接:https://leetcode-cn.com/problems/minimum-number-of-flips-to-make-the-binary-string-alternating/solution/shi-er-jin-zhi-zi-fu-chuan-zi-fu-jiao-ti-i52p/

    C++代码:

     1 class Solution {
     2 public:
     3     int minFlips(string s) {
     4         //示性函数
     5         auto I = [](char ch, int x) -> int {
     6             return ch - '0' == x;
     7         };
     8 
     9         int n = s.size();
    10         vector<vector<int>> pre(n, vector<int>(2));
    11 
    12         //注意 i=0 的边界情况
    13         for(int i=0 ; i<n ;++i)
    14         {
    15             pre[i][0]=(i==0 ? 0 : pre[i-1][1])+I(s[i],1);
    16             pre[i][1]=(i==0 ? 0 : pre[i-1][0])+I(s[i],0);
    17         }
    18         int ans = min(pre[n - 1][0], pre[n - 1][1]);
    19 
    20         //如果n是奇数,还需要求出suf
    21         if (n % 2 == 1) {
    22             // 如果 n 是奇数,还需要求出 suf
    23             vector<vector<int>> suf(n, vector<int>(2));
    24             // 注意 i=n-1 的边界情况
    25             for (int i = n - 1; i >= 0; --i) {
    26                 suf[i][0] = (i == n - 1 ? 0 : suf[i + 1][1]) + I(s[i], 1);
    27                 suf[i][1] = (i == n - 1 ? 0 : suf[i + 1][0]) + I(s[i], 0);
    28             }
    29             for (int i = 0; i + 1 < n; ++i) {
    30                 ans = min(ans, pre[i][0] + suf[i + 1][0]);
    31                 ans = min(ans, pre[i][1] + suf[i + 1][1]);
    32             }
    33         }
    34 
    35         return ans;
    36     }
    37 };
    雪儿言
  • 相关阅读:
    XML(学习笔记)
    css样式学习笔记
    Request(对象)
    sql一些错误修改的总结
    转载(如何学习C#)
    sql server(学习笔记2 W3Cschool)
    sql sqrver(学习笔记1 W3Cschool)
    关于 flutter开发碰到的各种问题,有的已经解决有的一直没解决或者用其他方法替代
    关于 Flutter IOS build It appears that your application still contains the default signing identifier.
    关于 flutter本地化问题 The getter 'pasteButtonLabel' was called on null
  • 原文地址:https://www.cnblogs.com/weixq351/p/14856689.html
Copyright © 2020-2023  润新知