每日一算法题-字符串排列

56 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第20天,点击查看活动详情

一、题目

描述

输入一个长度为 n 字符串,打印出该字符串中字符的所有排列,你可以以任意顺序返回这个字符串数组。
例如输入字符串ABC,则输出由字符A,B,C所能排列出来的所有字符串ABC,ACB,BAC,BCA,CBA和CAB。

image.png

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

vector<string> permutation(string& str) {
}

int main(int, char*[])
{
    string str = "aab";
    vector<string> res = permutation(str);
    for(string s : res){
        cout << s << endl;
    }
}

二、分析

由题意可知,排列问题是典型的递归应用场景之一,不过这里又有一点点特殊,因为这里需要排除重复,这个有一点难度,因为重复的情况各种各样,要兼容所有情况,只能建立hash表,但是这样效率就会大打折扣。

那有没有什么办法可以降低重复情况呢?

首先想到重复是因为字符重复导致,而导致情况各种各样的原因是重复字符分布无规律,知道问题,就能解决问题。

重复字符分布无规律,那我们就排个序。

字符重复,我们就在排列的时候检测一下,重复排列会出现两次,可以排除第一次重复,也可以排除第二次重复。

三、模拟

  1. 1
  2. 1 2 第一次重复
  3. 1 2 3
  4. 1
  5. 1 3
  6. 1 3 2
  7. 2 第二次重复,排除
  8. 3
  9. 3 1
  10. 3 1 2 第一次重复
  11. 3 2 第二次重复,排除

四、实现

void permutationDfs(vector<string>& res, string& str, string& temp, vector<int>& vis){
    if(temp.length() == str.length()){
        res.push_back(temp);
        return;
    }
    for(int i = 0; i < str.length(); ++i){
        if(vis[i]) continue;
        if(i > 0 && str[i - 1] == str[i] && !vis[i - 1]) continue;
        vis[i] = 1;
        temp.push_back(str[i]);
        permutationDfs(res, str, temp, vis);
        vis[i] = 0;
        temp.pop_back();
    }
}
vector<string> permutation(string& str) {
    std::sort(str.begin(), str.end());
    vector<int> vis(str.size(), 0);
    vector<string> res;
    string temp;
    permutationDfs(res, str, temp, vis);
    return res;
}

五、结言

要想解决问题,首先得知道问题出在哪里,然后再对症下药,就能药到病除。

创作不易,留个赞再走吧!如果对文章内容有任何指正,欢迎评论!