【数据结构-堆】力扣767. 重构字符串

给定一个字符串 s ,检查是否能重新排布其中的字母,使得两相邻的字符不同。

返回 s 的任意可能的重新排列。若不可行,返回空字符串 “” 。

示例 1:
输入: s = “aab”
输出: “aba”

示例 2:
输入: s = “aaab”
输出: “”

提示:
1 <= s.length <= 500
s 只包含小写字母

优先队列

class Solution {
public:
    string reorganizeString(string s) {
        if(s.size() < 2){
            return s;
        }

        int n = s.size();
        vector<int> counts(26, 0);
        int maxCount = 0;
        for(int i = 0; i < n; i++){
            counts[s[i] - 'a']++;
            maxCount = max(maxCount, counts[s[i] - 'a']);
        }
        if(maxCount > (n + 1) / 2){
            return "";
        }

        auto cmp = [&](const char& letter1, const char& letter2){
            return counts[letter1 - 'a'] < counts[letter2 - 'a'];
        };

        priority_queue<char, vector<char>, decltype(cmp)> q(cmp);
        for(char c = 'a'; c <= 'z'; c++){
            if(counts[c - 'a'] > 0){
                q.push(c);
            }
        }

        string new_s = "";
        while(q.size() > 1){
            char letter1 = q.top();
            q.pop();
            char letter2 = q.top();
            q.pop();
            new_s += letter1;
            new_s += letter2;
            counts[letter1 - 'a']--;
            counts[letter2 - 'a']--;
            if(counts[letter1 - 'a'] > 0){
                q.push(letter1);
            }

            if(counts[letter2 - 'a'] > 0){
                q.push(letter2);
            }
        }

        if(q.size() > 0){
            new_s += q.top();
        }
        return new_s;
    }
};

时间复杂度:O(nlog∣Σ∣+∣Σ∣)
空间复杂度:O(∣Σ∣)

这道题是基于贪心的思路,使用优先队列来完成。首先当s的长度小于2的时候,一定有重构字符串。接着当s中某个字符的个数大于字符串s长度的一半的时候(s长度如果是奇数则向上取整),那么则无法有重构字符串。接着我们使用贪心的思路,我们每次取出字符数量最多的两个字符,将他们加入到重构字符串new_s中。我们要比较字符数量最多的数量,可以用最大堆来做,cmp是我们自己写的比较函数。每次将最多数量的字符加入到new_s后,将他们数量都减去1,当他们数量还大于0的时候,才将它们继续加入到q中。

当q中只剩下一种字符,就加入new_s中。最后返回new_s。

这道题还可以用计数的贪心方法实现O(n)的算法,这里不涉及

### Java 实现 LeetCode 第 3 题:无重复字符的最长子串 以下是基于滑动窗口算法的 Java 解决方案,该方法通过维护一个动态窗口来高效解决问题。此解法的时间复杂度为 O(n),空间复杂度为 O(min(m, n)),其中 m 是字符串中不同字符的数量。 #### 滑动窗口原理 滑动窗口的核心思想是利用两个指针 `left` 和 `right` 来表示当前正在考察的子串范围。当发现有重复字符时,移动左边界直到不再存在重复字符为止[^1]。 ```java public class Solution { public int lengthOfLongestSubstring(String s) { if (s == null || s.length() == 0) return 0; int maxLength = 0; int left = 0; // 左边界初始位置 Map<Character, Integer> charIndexMap = new HashMap<>(); for (int right = 0; right < s.length(); right++) { // 右边界逐步扩展 char currentChar = s.charAt(right); if (charIndexMap.containsKey(currentChar) && charIndexMap.get(currentChar) >= left) { // 如果当前字符已经存在于哈希表中,则更新左边界到上一次出现的位置之后 left = charIndexMap.get(currentChar) + 1; } charIndexMap.put(currentChar, right); // 更新或记录当前字符及其索引 maxLength = Math.max(maxLength, right - left + 1); // 计算最大长度 } return maxLength; } } ``` 上述代码实现了以下逻辑: - 使用 `HashMap` 存储每个字符最近一次出现的索引。 - 当遇到重复字符时,调整左边界至之前重复字符的下一个位置。 - 动态计算并保存最大的无重复子串长度[^2]。 #### 测试案例 为了验证程序的有效性,可以运行如下测试: ```java public static void main(String[] args) { Solution sol = new Solution(); System.out.println(sol.lengthOfLongestSubstring("abcabcbb")); // 输出: 3 ["abc"] System.out.println(sol.lengthOfLongestSubstring("bbbbb")); // 输出: 1 ["b"] System.out.println(sol.lengthOfLongestSubstring("pwwkew")); // 输出: 3 ["wke"] System.out.println(sol.lengthOfLongestSubstring("")); // 输出: 0 [] System.out.println(sol.lengthOfLongestSubstring("au")); // 输出: 2 ["au"] } ``` 这些测试涵盖了多种情况,包括空字符串、全相同字符以及正常输入场景下的表现[^3]。 #### 复杂度分析 时间复杂度:O(n),因为每个字符最多被访问两次——一次由右指针遍历,另一次可能因左指针移动而重新评估。 空间复杂度:O(min(m, n)),取决于字符串中的唯一字符数量与总长度之间的较小者[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值