力扣 每日一题 927. 三等分难度:困难,rating: 1994(思维+后缀字符串+bitset技巧)

Posted nefu-ljw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了力扣 每日一题 927. 三等分难度:困难,rating: 1994(思维+后缀字符串+bitset技巧)相关的知识,希望对你有一定的参考价值。

题目链接

https://leetcode.cn/problems/three-equal-parts/

题目来源于:第107场周赛 Q3 rating: 1994

思路

为了方便表述,本文将数组或子数组称之为“字符串”或“子串”。

本题的关键在于发现:

  1. 字符串能被三等分 => 1的总个数必须是3的倍数。必须满足这个必要条件
  2. 第3个子串的结束位置被固定在串的末尾,那么第3个子串的后缀0的个数suffix_zero_count,能用于限制前面第1、2个子串的后缀0个数。因为第3个子串的后缀0是固定的,而前面的两个子串的后缀0是可以往后调整的,只要它们的后缀0个数>=suffix_zero_count,多余的后缀0就可以划分给下一个子串作为前导0。通过这种调整,确定了第1、2个子串的结束位置,同时也确定了第2、3个子串的开始位置(第1个子串的开始位置被固定在串的开头)。
  3. 最后直接得到三个子串的起始和终点位置,依次比对是否相等即可。

放一个图便于理解:

代码

先切分得到string,再用其初始化bitset,bitset能直接判断是否相等(包括前导0也没有问题)。

class Solution 
public:
    vector<int> threeEqualParts(vector<int>& arr) 
        int sz=arr.size();
        vector<int> ans;
        string str;
        int count=0; // 1的总个数
        for(auto &x:arr)
            if(x==1)
                count++;
            
            str+=(x+'0'); // arr to string
        
        // 全是0,没有1,可以任意划分,只要不超过边界即可
        if(count==0)
            return 0,sz-1;
        
        // 1的个数不是3的倍数,划分失败
        if(count%3!=0)
            return -1,-1;
        
        int ave_count=count/3; // 每个子串含有的1的个数
        int end_pos1=-1,start_pos2=-1,end_pos2=-1,start_pos3=-1,end_pos3=-1;
        int now_count=0;
        for(int i=0;i<sz;i++)
            if(arr[i]==1)
                now_count++;
                if(now_count==ave_count)
                    end_pos1=i; // 第1个子串中最后一个1的位置
                
                if(now_count==ave_count+1)
                    start_pos2=i; // 第2个子串中第一个1的位置
                
                if(now_count==ave_count*2)
                    end_pos2=i; // 第2个子串中最后一个1的位置
                
                if(now_count==ave_count*2+1)
                    start_pos3=i; // 第3个子串中第一个1的位置
                
                if(now_count==(ave_count*3))
                    end_pos3=i; // 第3个子串中最后一个1的位置
                
            
        

        // 第3个子串后缀0的区间[end_pos3+1, sz)
        int suffix_zero_count=sz-end_pos3-1; // 第3个子串的后缀0个数
        if(start_pos3-end_pos2-1<suffix_zero_count || start_pos2-end_pos1-1<suffix_zero_count)
            // 第2个子串后缀0的区间[end_pos2+1,start_pos3)
            // 第1个子串后缀0的区间[end_pos1+1,start_pos2)
            // 若第1个子串或第2个子串的后缀0个数不够第3个子串的后缀0个数,则划分失败
            return -1,-1;
        
        
        // 切分得到s1
        int suffix_end_pos1=end_pos1+suffix_zero_count; // s1加上后缀0,调整s1的结束位置
        assert(suffix_end_pos1<start_pos2);
        string s1=str.substr(0,suffix_end_pos1+1); // [0,suffix_end_pos1]
		
        // 切分得到s2
        int suffix_end_pos2=end_pos2+suffix_zero_count; // s2加上后缀0,调整s2的结束位置
        assert(suffix_end_pos2<start_pos3);
        string s2=str.substr(start_pos2,suffix_end_pos2-start_pos2+1); // [start_pos2,suffix_end_pos2]
		
        // 切分得到s3
        string s3=str.substr(start_pos3); // [start_pos3,sz)

        bitset<30000> t1(s1);
        bitset<30000> t2(s2);
        bitset<30000> t3(s3);
        if(t1==t2&&t2==t3) // bitset直接判断是否相等
            return suffix_end_pos1,suffix_end_pos2+1;
        else
            return -1,-1;
        
    
;

/*
[1,0,1,0,1]
ans: [0,3]

[1,1,1,0,0,1,1,0,1,0,1,1,1,1,1,1]
ans: [-1,-1]
*/

以上是关于力扣 每日一题 927. 三等分难度:困难,rating: 1994(思维+后缀字符串+bitset技巧)的主要内容,如果未能解决你的问题,请参考以下文章

每日一题927. 三等分

每日一题927. 三等分

927. 三等分 : 一道模拟题

力扣 每日一题 1250. 检查「好数组」难度:困难,rating: 1983(数论)

力扣 每日一题 768. 最多能完成排序的块 II难度:困难,rating: 1787(区间合并+区间计数)

力扣 每日一题 1235. 规划兼职工作难度:困难,rating: 2022(动态规划+二分查找)