zoukankan      html  css  js  c++  java
  • 【LeetCode & 剑指offer刷题】字符串题9:38 字符串的排列(全排列问题)

    【LeetCode & 剑指offer 刷题笔记】目录(持续更新中...)

    38 字符串的排列(全排列问题)

    题目描述

    输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

    输入描述:

    输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
     
    /*
    问题:全排列(含重复元素,且要求按字典序输出)
    方法一:交换法,递归
    用哈希表记录,以解决存在重复元素的全排列问题
    参考问题总结“排列与组合”
    */
    class Solution
    {
    public:
        vector<string> Permutation(string str)
        {
            vector<string> result;
            if(str.empty()) return result;
            per(str, 0, result);
            sort(result.begin(), result.end()); //排序,以便之后产生字典序的全排列(这里是产生序列之后再排序,通过改进算法可以实现按字典序push)
            return result;
        }
    private:
        void per(string& str, int begin, vector<string>& result)
        {
            if(begin >= str.size()-1)
            {
                result.push_back(str);
                return;
            }
            else
            {
                unordered_set<char> record; //记录出现过的字符
                for(int i = begin; i<str.size(); i++) //产生排列的多个分支
                {
                    if(record.find(str[i]) == record.end()) //只和没交换过的交换
                    {
                        record.insert(str[i]);
                        swap(str[begin], str[i]); //与后面元素交换,以产生不同字符开头的排列
                        per(str, begin+1, result); //递归产生分支的深度
                        swap(str[begin], str[i]); //归位,以便下次交换                   
                    }
                }
            }
           
        }
    };
     
    /*
    方法二:dfs(掌握)
    map记录,以解决存在重复元素的全排列问题
    */
    class Solution
    {
    public:
        vector<string> Permutation(string str)
        {
          
            vector<string> result;
            if(str.empty()) return result;
           
            string path;
            map<char,int> counter; //map时,key值存储为有序的,最后输出的排列也是有序的      
           // sort(str.begin(), str.end()); //上面用了map,故这里无需先sort      
            for(char a:str) counter[a]++; //统计str中各数出现的次数,没有key的时候会自动创建      
            dfs(str, result, path, counter);//递归
            return result;
        }
    private:
        void dfs(string& str, vector<string>& result, string& path, map<char, int>& counter)
        {
            if(path.size() == str.size()) //到达树的末尾,将单路径数组push到结果向量中
            {
                result.push_back(path);
                return;
            }
          
            for(auto& p:counter) //for循环带来的是树宽度方向的延伸,即产生同一层的多个分支
            {
                if(p.second>0) //如果该元素没有被取完(某个元素可能会出现多次)
                {
                    path.push_back(p.first);
                    p.second--; //已经取了这个元素,统计数减一
                    dfs(str, result, path, counter); //继续往深度方向延伸
                    path.pop_back();  //回溯,给其他分支腾空间!!
                    p.second++;
                }
            }
        }
    };
     
     
    567. Permutation in String
    Given two strings s1 and s2, write a function to return true if s2 contains the permutation of s1. In other words, one of the first string's permutations is the substring of the second string.
    Example 1:
    Input:s1 = "ab" s2 = "eidbaooo"
    Output:True
    Explanation: s2 contains one permutation of s1 ("ba").
    Example 2:
    Input:s1= "ab" s2 = "eidboaoo"
    Output: False
    Note:
    1. The input strings only contain lower case letters.
    2. The length of both given strings is in range [1, 10,000].

     
    /*
    问题:判断s1的全排列中是否有排列是s2的子串
    统计表+滑动窗口
    统计s1各字符出现的次数,并用s1长度的滑动窗框住s2,统计各滑动窗各字符出现的次数,如果与s1中相等,则返回true
    */
    class Solution
    {
    public:
        bool checkInclusion(string s1, string s2)
        {
            if(s1.empty() || s2.empty()) return false;
           
            int n1 = s1.size(), n2 = s2.size();
            vector<int> m1(128), m2(128);//统计表(也可用hash表)
           
            for (int i = 0; i < n1; ++i) //对s1,s2中前n1个字符统计
            {
                m1[s1[i]]++; m2[s2[i]]++;
            }
           
            if (m1 == m2) return true; //若各字符出现的次数相等,说明可以由s1排列得到当前s2中的子串
           
            for (int i = n1; i < n2; ++i) //滑动窗口扫描s2
            {
                m2[s2[i]]++;
                m2[s2[i - n1]]--;
                if (m1 == m2) return true;
            }
            return false;
        }
    };
     
     
  • 相关阅读:
    浅谈prufer编码
    数据结构训练之三
    博弈论训练之一
    动态规划训练之十三
    杂题训练之七
    奇技淫巧训练之八
    浅谈博弈论
    浅谈卡特兰数
    奇技淫巧训练之七
    浅谈概率期望的一些例题
  • 原文地址:https://www.cnblogs.com/wikiwen/p/10224844.html
Copyright © 2011-2022 走看看