3388. 统计数组中的美丽分割(dp动态规划或者字符串哈希)

https://leetcode.cn/problems/count-beautiful-splits-in-an-array/description/

给你一个整数数组\(nums\)
如果数组\(nums\)的一个分割满足以下条件,我们称它是一个 美丽 分割:

  1. 数组\(nums\)分为三段非空子数组:\(nums_1\)\(nums_2\)\(nums_3\),三个数组\(nums_1\)\(nums_2\)\(nums_3\) 按顺序连接可以得到 nums。
  2. 子数组\(nums_1\)是子数组\(nums_2\)前缀 或者\(nums_2\)\(nums_3\)前缀
    请你返回满足以上条件的分割 数目
    子数组 指的是一个数组里一段连续 非空 的元素。
    前缀 指的是一个数组从头开始到中间某个元素结束的子数组。

示例 1:
输入:nums = [1,1,2,1]
输出:2
解释:
美丽分割如下:
nums1 = [1] ,nums2 = [1,2] ,nums3 = [1] 。
nums1 = [1] ,nums2 = [1] ,nums3 = [2,1] 。

示例 2:
输入:nums = [1,2,3,4]
输出:0
解释:
没有美丽分割。

提示:
1 <= nums.length <= 5000
0 <= nums[i] <= 50

首先这个题看到应该就要想起来字符串哈希,就是O(n^2)枚举第二个和第三个开始。
枚举i,j。就是第一个为[0,i-1],第二个为[i,j-1],第三个是[j,n-1].
解法一:字符串华哈希

typedef unsigned long long ull;
const int N=1e4+10,P=131;
class Solution {
    ull p[N],h[N];
    void init(vector<int>& s){
        int n=s.size();
        p[0]=1;
        for(int i=1;i<=n;i++){
            h[i]=h[i-1]*P+s[i-1];
            p[i]=p[i-1]*P;
        }
    }
    ull get(int l,int r){
        return h[r+1]-h[l]*p[r-l+1];
    }
    bool ISpre(int l1,int r1,int l2,int r2){
        int len1=r1-l1+1;
        int len2=r2-l2+1;
        if(len1>len2) return false;
        return get(l1,r1)==get(l2,l2+len1-1);
    }
public:
    int beautifulSplits(vector<int>& nums) {
        int n=nums.size();
        if(n<3) return 0;
        init(nums);
        int count=0;
        for(int i=1;i<n-1;i++){//枚举第二个开始
            for(int j=i+1;j<n;j++){//第三个开始
                if(ISpre(0,i-1,i,j-1)||ISpre(i,j-1,j,n-1)){
                    count++;
                }
            }
        }
        return count;
    }
};

解法二:
定义 lcp[i][j] 表示后缀 nums[i:] 和后缀 nums[j:] 的最长公共前缀(Longest Common Prefix)的长度。
对于这个lcp[i][j],就是比如说字符串为abcabcd,那么dp[1][1]=7,dp[1][4]=3.

class Solution {
public:
    int beautifulSplits(vector<int>& nums) {
        int n=nums.size();
        vector f(n+1,vector<int>(n+1));
        for(int i=n-1;i>=0;i--){
            for(int j=n-1;j>=i;j--){
                if(nums[i]==nums[j]){
                    f[i][j]=f[i+1][j+1]+1;
                }
            }
        }//f[0][0]=4
        int ans=0;
        for(int i=0;i<n;i++){
            for(int j=i+1;j+1<n;j++){
                int len1=i+1,len2=j-i,len3=n-1-j;
                if((len1<=len2&&f[0][i+1]>=len1)||(len2<=len3&&f[i+1][j+1]>=len2)) ans++;
            }
        }
        return ans;
    }
};
posted @ 2024-12-21 20:36  lipu123  阅读(27)  评论(0)    收藏  举报