20240122-具有唯一字符的连接字符串的最大长度

本文介绍如何利用回溯和set实现对给定字符串数组中组成唯一字符序列的最长字符串的求解,涉及算法设计和空间效率分析。
摘要由CSDN通过智能技术生成

题目要求

给你一个字符串数组 arr。字符串 s 由 arr 中具有唯一字符的子序列连接而成。

请返回 s 的最大可能长度。

子序列是一个数组,它可以在不改变其余元素顺序的情况下,通过删除某些元素或不删除任何元素从另一个数组派生出来。

简单来说我们需要组成尽可能长的字符串并且保证出现的字符是唯一的。

Example 1:

Input: arr = ["un","iq","ue"]
Output: 4
Explanation: All the valid concatenations are:
- ""
- "un"
- "iq"
- "ue"
- "uniq" ("un" + "iq")
- "ique" ("iq" + "ue")
Maximum length is 4.

Example 2:

Input: arr = ["cha","r","act","ers"]
Output: 6
Explanation: Possible longest valid concatenations are "chaers" ("cha" + "ers") and "acters" ("act" + "ers").

Example 3:

Input: arr = ["abcdefghijklmnopqrstuvwxyz"]
Output: 26
Explanation: The only string in arr has all 26 characters.

思路

找到由数组中的字符串组合而成的最长唯一字符串。关键点在于“唯一字符”,即任何字符在最终字符串中只能出现一次。

考虑使用‘set’追踪字符唯一性:‘set’自然的保证了其中元素的唯一性,因为不允许重复元素存在。

同一个字符串中的重复元素检查,采用‘insert’方法来判断返回值是否已经存在于‘set’中,如果插入的是已经存在的字符,会返回false。

采用回溯算法逐一探索所有可能的字符串组合。在每一步中:

  • 如果当前考虑的字符串可以无重复地加入到当前组合中,我们就更新当前字符串组合和字符集合,然后递归地探索下一个选择。
  • 完成探索后,通过“回溯”操作撤销上一步的选择,即从当前字符串组合中移除刚才添加的字符串,并从字符集合中删除相应的字符,以恢复到加入新字符串之前的状态。

代码

class Solution {
public:
    bool isUnique(const string& str, const set<char>& currentSet) {
        set<char> strSet;
        for (char c : str) {
            if (currentSet.find(c) != currentSet.end() || !strSet.insert(c).second) {
                return false;
            }
        }
        return true;
    }

    void backtrack(vector<string>& arr, int startIndex, set<char>& currentSet, string& currentString, int& maxLength) {
        maxLength = max(maxLength, static_cast<int>(currentString.size()));

        for (int i = startIndex; i < arr.size(); ++i) {
            if (isUnique(arr[i], currentSet)) {
                for (char c : arr[i]) {
                    currentSet.insert(c);
                }
                currentString += arr[i];
                backtrack(arr, i+1, currentSet, currentString, maxLength);

                for (char c : arr[i]) {
                    currentSet.erase(c);
                }
                currentString.erase(currentString.size() - arr[i].size());
            }
        }
    }

    int maxLength(vector<string>& arr) {
        int maxLength = 0;
        set<char> currentSet;
        string currentString = "";
        backtrack(arr, 0, currentSet, currentString, maxLength);
        return maxLength;
    }
};

时间复杂度

空间复杂度

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值