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;
        }
    };
     
     
  • 相关阅读:
    从Oracle提供两种cube产品说开
    Sql Server DWBI的几个学习资料
    Unload Oracle data into text file
    初学Java的几个tips
    我常用的Oracle知识点汇总
    benefits by using svn
    如何在windows上使用putty来显示远端linux的桌面
    building commercial website using Microsoft tech stack
    Understand Thread and Lock
    Update google calendar by sunbird
  • 原文地址:https://www.cnblogs.com/wikiwen/p/10224844.html
Copyright © 2011-2022 走看看