• 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 };
    雪儿言
  • 相关阅读:
    漏洞扫描
    端口探测
    IP探测
    kali linux基础命令
    python学习07
    python学习06
    openoffice+jquery.media.js实现Linux与Windows中文档在线预览
    Oracle10g安装包
    MyEclipse2014安装包附注册破解包、eclipse安装包
    外层div自适应内层div高度
  • 原文地址:https://www.cnblogs.com/weixq351/p/14856689.html
Copyright © 2020-2023  润新知