字符串的排列


title: 2019-8-24 字符串的排列
tags: 算法,每日一题,字符串


字符串的排列

1. 题目描述

输入一个字符串,按字典序打印出该字符串中字符的所有排列,输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

2.题目解析

首先对于给定的一个字符串比如abc,对于第一个位置我们可以有三种选择,a,b,c。所以只需要每次都把字符串对应的字符换到第一个位置即可。比如现在我们把b换到了第一个位置bac,那么这个时候相当于固定了第一个位置的字符了,对于后面的字符的处理就和之前的一样了(ok构成了递归了)。因此只要递归下去就可以解决问题了。但是这是没有考虑字符串中有重复元素的情况。

对于字符串中包含重复字符的情况,我们可能会尝试如果要交换的字符相同的我们就不交换,但是对于abb ,第一次aa交换不变,第二次ab交换得到bab,第三次bba。显然第三次的递归会得到一个bba的结果,第二次的bab也会得到一个bba的结果。所以这种尝试是无效的。现在尝试策略二:在当前这次递归中,如果从from到当前交换的位置之间都没有相同的元素(保证之前没有出现固定当前元素的情况)。

这两个问题解决之后还有一个问题就是按照字典序输出,这需要在每次进行下一次递归之前对从from到to之间的元素进行一次字典排序即可。

2.1 思路解析

1、只考虑全排列的情况

2、考虑用重复的情况

错误的方式,相同的字符不交换

正确的情况:从交换位置处ifrom之间如果有和i相同的字符就不交换也不会递归下去

3、需要字典排序的字符串全排列

class Solution {
public:
    vector<string> Permutation(string str) {
        vector<string> res;
        if(str.empty()) return res;
        sort(str.begin(), str.end());
        permutation_recru(str, 0, str.size()-1, res);
        return res;
    }
    
    void permutation_recru(string& str,int from, int to, vector<string>& res){
        if(from == to) {
            res.push_back(str);
            return;
        }
        for(int i=from; i<=to; ++i){
            sort(str.begin() + from, str.end());//这个只能放在这个位置
            if(isSwap(str, from, i)){
                swap(str, from, i);
                permutation_recru(str, from+1, to, res);
                swap(str, from, i);
            }
        }
    }
    
    void swap(string& str, int a, int b){
        char temp = str[a];
        str[a] = str[b];
        str[b] = temp;
    }
    
    bool isSwap(string& str, int from, int to){
        for(int i=from; i<to; ++i){
            if(str[i] == str[to]) return false;
        }
        return true;
    }
};

更多关于编程和机器学习资料请关注FlyAI公众号。
公众号二维码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值