列表

详情


2983. 回文串重新排列查询

给你一个长度为 偶数 n ,下标从 0 开始的字符串 s 。

同时给你一个下标从 0 开始的二维整数数组 queries ,其中 queries[i] = [ai, bi, ci, di] 。

对于每个查询 i ,你需要执行以下操作:

对于每个查询,你的任务是判断执行操作后能否让 s 变成一个 回文串

每个查询与其他查询都是 独立的 。

请你返回一个下标从 0 开始的数组 answer ,如果第 i 个查询执行操作后,可以将 s 变为一个回文串,那么 answer[i] = true,否则为 false 。

 

示例 1:

输入:s = "abcabc", queries = [[1,1,3,5],[0,2,5,5]]
输出:[true,true]
解释:这个例子中,有 2 个查询:
第一个查询:
- a0 = 1, b0 = 1, c0 = 3, d0 = 5
- 你可以重新排列 s[1:1] => abcabc 和 s[3:5] => abcabc 。
- 为了让 s 变为回文串,s[3:5] 可以重新排列得到 => abccba 。
- 现在 s 是一个回文串。所以 answer[0] = true 。
第二个查询:
- a1 = 0, b1 = 2, c1 = 5, d1 = 5.
- 你可以重新排列 s[0:2] => abcabc 和 s[5:5] => abcabc 。
- 为了让 s 变为回文串,s[0:2] 可以重新排列得到 => cbaabc 。
- 现在 s 是一个回文串,所以 answer[1] = true 。

示例 2:

输入:s = "abbcdecbba", queries = [[0,2,7,9]]
输出:[false]
解释:这个示例中,只有一个查询。
a0 = 0, b0 = 2, c0 = 7, d0 = 9.
你可以重新排列 s[0:2] => abbcdecbba 和 s[7:9] => abbcdecbba 。
无法通过重新排列这些子字符串使 s 变为一个回文串,因为 s[3:6] 不是一个回文串。
所以 answer[0] = false 。

示例 3:

输入:s = "acbcab", queries = [[1,2,4,5]]
输出:[true]
解释:这个示例中,只有一个查询。
a0 = 1, b0 = 2, c0 = 4, d0 = 5.
你可以重新排列 s[1:2] => acbcab 和 s[4:5] => acbcab 。
为了让 s 变为回文串,s[1:2] 可以重新排列得到 => abccab 。
然后 s[4:5] 重新排列得到 abccba 。
现在 s 是一个回文串,所以 answer[0] = true 。

 

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: vector<bool> canMakePalindromeQueries(string s, vector<vector<int>>& queries) { } };

cpp 解法, 执行用时: 520 ms, 内存消耗: 245.2 MB, 提交时间: 2024-01-01 19:27:15

class Solution {
public:
    vector<bool> canMakePalindromeQueries(string s, vector<vector<int>> &queries) {
        // 分成左右两半,右半反转
        int n = s.length() / 2;
        string t = s.substr(n);
        reverse(t.begin(), t.end());

        // 预处理三种前缀和
        vector<vector<int>> sum_s(n + 1, vector<int>(26));
        for (int i = 0; i < n; i++) {
            sum_s[i + 1] = sum_s[i];
            sum_s[i + 1][s[i] - 'a']++;
        }

        vector<vector<int>> sum_t(n + 1, vector<int>(26));
        for (int i = 0; i < n; i++) {
            sum_t[i + 1] = sum_t[i];
            sum_t[i + 1][t[i] - 'a']++;
        }

        vector<int> sum_ne(n + 1);
        for (int i = 0; i < n; i++) {
            sum_ne[i + 1] = sum_ne[i] + (s[i] != t[i]);
        }

        // 计算子串中各个字符的出现次数,闭区间 [l,r]
        auto count = [](vector<vector<int>> &sum, int l, int r) -> vector<int> {
            auto res = sum[r + 1];
            for (int i = 0; i < 26; i++) {
                res[i] -= sum[l][i];
            }
            return res;
        };

        auto subtract = [](vector<int> s1, vector<int> s2) -> vector<int> {
            for (int i = 0; i < 26; i++) {
                s1[i] -= s2[i];
                if (s1[i] < 0) {
                    return {};
                }
            }
            return s1;
        };

        auto check = [&](int l1, int r1, int l2, int r2, vector<vector<int>> &sumS, vector<vector<int>> &sumT) -> bool {
            if (sum_ne[l1] > 0 || // [0,l1-1] 有 s[i] != t[i]
                sum_ne[n] - sum_ne[max(r1, r2) + 1] > 0) { // [max(r1,r2)+1,n-1] 有 s[i] != t[i]
                return false;
            }
            if (r2 <= r1) { // 区间包含
                return count(sumS, l1, r1) == count(sumT, l1, r1);
            }
            if (r1 < l2) { // 区间不相交
                return sum_ne[l2] - sum_ne[r1 + 1] == 0 && // [r1+1,l2-1] 都满足 s[i] == t[i]
                       count(sumS, l1, r1) == count(sumT, l1, r1) &&
                       count(sumS, l2, r2) == count(sumT, l2, r2);
            }
            // 区间相交但不包含
            auto s1 = subtract(count(sumS, l1, r1), count(sumT, l1, l2 - 1));
            auto s2 = subtract(count(sumT, l2, r2), count(sumS, r1 + 1, r2));
            return !s1.empty() && !s2.empty() && s1 == s2;
        };

        vector<bool> ans(queries.size());
        for (int i = 0; i < queries.size(); i++) {
            auto &q = queries[i];
            int l1 = q[0], r1 = q[1], l2 = n * 2 - 1 - q[3], r2 = n * 2 - 1 - q[2];
            ans[i] = l1 <= l2 ? check(l1, r1, l2, r2, sum_s, sum_t) :
                                check(l2, r2, l1, r1, sum_t, sum_s);
        }
        return ans;
    }
};

java 解法, 执行用时: 70 ms, 内存消耗: 126.1 MB, 提交时间: 2024-01-01 19:27:02

class Solution {
    public boolean[] canMakePalindromeQueries(String S, int[][] queries) {
        char[] s = S.toCharArray();
        int m = s.length;
        int n = m / 2;

        // 预处理三种前缀和
        int[][] sumS = new int[n + 1][26];
        for (int i = 0; i < n; i++) {
            sumS[i + 1] = sumS[i].clone();
            sumS[i + 1][s[i] - 'a']++;
        }

        int[][] sumT = new int[n + 1][26];
        for (int i = 0; i < n; i++) {
            sumT[i + 1] = sumT[i].clone();
            sumT[i + 1][s[m - 1 - i] - 'a']++;
        }

        int[] sumNe = new int[n + 1];
        for (int i = 0; i < n; i++) {
            sumNe[i + 1] = sumNe[i] + (s[i] != s[m - 1 - i] ? 1 : 0);
        }

        boolean[] ans = new boolean[queries.length];
        for (int i = 0; i < queries.length; i++) {
            int[] q = queries[i];
            int l1 = q[0], r1 = q[1], l2 = m - 1 - q[3], r2 = m - 1 - q[2];
            ans[i] = l1 <= l2 ? check(l1, r1, l2, r2, sumS, sumT, sumNe) :
                                check(l2, r2, l1, r1, sumT, sumS, sumNe);
        }
        return ans;
    }

    private boolean check(int l1, int r1, int l2, int r2, int[][] sumS, int[][] sumT, int[] sumNe) {
        if (sumNe[l1] > 0 || // [0,l1-1] 有 s[i] != t[i]
            sumNe[sumNe.length - 1] - sumNe[Math.max(r1, r2) + 1] > 0) { // [max(r1,r2)+1,n-1] 有 s[i] != t[i]
            return false;
        }
        if (r2 <= r1) { // 区间包含
            return Arrays.equals(count(sumS, l1, r1), count(sumT, l1, r1));
        }
        if (r1 < l2) { // 区间不相交
            return sumNe[l2] - sumNe[r1 + 1] <= 0 && // [r1+1,l2-1] 都满足 s[i] == t[i]
                   Arrays.equals(count(sumS, l1, r1), count(sumT, l1, r1)) &&
                   Arrays.equals(count(sumS, l2, r2), count(sumT, l2, r2));
        }
        // 区间相交但不包含
        int[] s1 = subtract(count(sumS, l1, r1), count(sumT, l1, l2 - 1));
        int[] s2 = subtract(count(sumT, l2, r2), count(sumS, r1 + 1, r2));
        return s1 != null && s2 != null && Arrays.equals(s1, s2);
    }

    // 计算子串中各个字符的出现次数,闭区间 [l,r]
    private int[] count(int[][] sum, int l, int r) {
        int[] res = sum[r + 1].clone();
        for (int i = 0; i < 26; i++) {
            res[i] -= sum[l][i];
        }
        return res;
    }

    private int[] subtract(int[] s1, int[] s2) {
        for (int i = 0; i < 26; i++) {
            s1[i] -= s2[i];
            if (s1[i] < 0) {
                return null;
            }
        }
        return s1;
    }
}

golang 解法, 执行用时: 196 ms, 内存消耗: 83.2 MB, 提交时间: 2024-01-01 19:26:44

func canMakePalindromeQueries(s string, queries [][]int) []bool {
	// 分成左右两半,右半反转
	n := len(s) / 2
	t := []byte(s[n:])
	slices.Reverse(t)
	s = s[:n]

	// 预处理三种前缀和
	sumS := make([][26]int, n+1)
	for i, b := range s {
		sumS[i+1] = sumS[i]
		sumS[i+1][b-'a']++
	}

	sumT := make([][26]int, n+1)
	for i, b := range t {
		sumT[i+1] = sumT[i]
		sumT[i+1][b-'a']++
	}

	sumNe := make([]int, n+1)
	for i := range s {
		sumNe[i+1] = sumNe[i]
		if s[i] != t[i] {
			sumNe[i+1]++
		}
	}

	// 计算子串中各个字符的出现次数,闭区间 [l,r]
	count := func(sum [][26]int, l, r int) []int {
		res := sum[r+1]
		for i, s := range sum[l][:] {
			res[i] -= s
		}
		return res[:]
	}

	subtract := func(s1, s2 []int) []int {
		for i, s := range s2 {
			s1[i] -= s
			if s1[i] < 0 {
				return nil
			}
		}
		return s1
	}

	check := func(l1, r1, l2, r2 int, sumS, sumT [][26]int) bool {
		if sumNe[l1] > 0 || // [0,l1-1] 有 s[i] != t[i]
			sumNe[n]-sumNe[max(r1, r2)+1] > 0 { // [max(r1,r2)+1,n-1] 有 s[i] != t[i]
			return false
		}
		if r2 <= r1 { // 区间包含
			return slices.Equal(count(sumS, l1, r1), count(sumT, l1, r1))
		}
		if r1 < l2 { // 区间不相交
			return sumNe[l2]-sumNe[r1+1] == 0 && // [r1+1,l2-1] 都满足 s[i] == t[i]
				slices.Equal(count(sumS, l1, r1), count(sumT, l1, r1)) &&
				slices.Equal(count(sumS, l2, r2), count(sumT, l2, r2))
		}
		// 区间相交但不包含
		s1 := subtract(count(sumS, l1, r1), count(sumT, l1, l2-1))
		s2 := subtract(count(sumT, l2, r2), count(sumS, r1+1, r2))
		return s1 != nil && s2 != nil && slices.Equal(s1, s2)
	}

	ans := make([]bool, len(queries))
	for i, q := range queries {
		l1, r1, l2, r2 := q[0], q[1], n*2-1-q[3], n*2-1-q[2]
		if l1 <= l2 {
			ans[i] = check(l1, r1, l2, r2, sumS, sumT)
		} else {
			ans[i] = check(l2, r2, l1, r1, sumT, sumS)
		}
	}
	return ans
}

python3 解法, 执行用时: 692 ms, 内存消耗: 77.5 MB, 提交时间: 2024-01-01 19:26:28

class Solution:
    def canMakePalindromeQueries(self, s: str, queries: List[List[int]]) -> List[bool]:
        # 分成左右两半,右半反转
        n = len(s) // 2
        t = s[n:][::-1]
        s = s[:n]

        # 预处理三种前缀和
        sum_s = [[0] * 26 for _ in range(n + 1)]
        for i, b in enumerate(s):
            sum_s[i + 1] = sum_s[i][:]
            sum_s[i + 1][ord(b) - ord('a')] += 1

        sum_t = [[0] * 26 for _ in range(n + 1)]
        for i, b in enumerate(t):
            sum_t[i + 1] = sum_t[i][:]
            sum_t[i + 1][ord(b) - ord('a')] += 1

        sum_ne = list(accumulate((x != y for x, y in zip(s, t)), initial=0))

        # 计算子串中各个字符的出现次数,闭区间 [l,r]
        def count(sum: List[List[int]], l: int, r: int) -> List[int]:
            return [x - y for x, y in zip(sum[r + 1], sum[l])]

        def subtract(s1: List[int], s2: List[int]) -> List[int]:
            for i, s in enumerate(s2):
                s1[i] -= s
                if s1[i] < 0:
                    return False
            return s1

        def check(l1: int, r1: int, l2: int, r2: int, sumS: List[List[int]], sumT: List[List[int]]) -> bool:
            # [0,l1-1] 有 s[i] != t[i] 或者 [max(r1,r2)+1,n-1] 有 s[i] != t[i]
            if sum_ne[l1] > 0 or sum_ne[n] - sum_ne[max(r1, r2) + 1] > 0:
                return False
            if r2 <= r1:  # 区间包含
                return count(sumS, l1, r1) == count(sumT, l1, r1)
            if r1 < l2:  # 区间不相交
                # [r1+1,l2-1] 都满足 s[i] == t[i]
                return sum_ne[l2] - sum_ne[r1 + 1] == 0 and \
                    count(sumS, l1, r1) == count(sumT, l1, r1) and \
                    count(sumS, l2, r2) == count(sumT, l2, r2)
            # 区间相交但不包含
            s1 = subtract(count(sumS, l1, r1), count(sumT, l1, l2 - 1))
            s2 = subtract(count(sumT, l2, r2), count(sumS, r1 + 1, r2))
            return s1 and s2 and s1 == s2

        ans = [False] * len(queries)
        for i, (l1, r1, c, d) in enumerate(queries):
            l2, r2 = n * 2 - 1 - d, n * 2 - 1 - c
            ans[i] = check(l1, r1, l2, r2, sum_s, sum_t) if l1 <= l2 else \
                     check(l2, r2, l1, r1, sum_t, sum_s)
        return ans

上一题