排序 - leetcode - 242. 有效的字母异位词

题目

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

示例 1:

输入: s = "anagram", t = "nagaram"
输出: true
示例 2:

输入: s = "rat", t = "car"
输出: false
说明:
你可以假设字符串只包含小写字母。

进阶:
如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?

解法

如果将s和t进行排序,然后判断两个字符串是否一样
下面通过各种排序方法来解决,可以理解所有的排序方法
我们按照从小到大开始排序

冒泡

先找到最大的,然后放在倒数第一位;
再找次大的,放在倒数第二位;
再第三大的,放在倒数第三位;
以此类推

注意事项

假如字符串长度n,其实找到前n-1大的即可,因为剩下的那个肯定是最小值;

代码

class Solution {
public:
    bool isAnagram(string s, string t) {
        if(s.size() != t.size()){
            return false;
        }

        char* p_s = (char*)s.c_str();
        char* p_t = (char*)t.c_str();

        buddleSort(p_s, s.size());
        buddleSort(p_t, t.size());

        printf("%s, %s\n", p_s, p_t);
        for(int i=0;i<s.size();i++){
            if(p_s[i] != p_t[i]){
                return false;
            }
        }
        return true;
    }

    void buddleSort(char* s, int s_len){
        for(int i = 0;i<s_len-1;i++){
            for(int j=0;j<s_len-1-i;j++){
                if(s[j]>s[j+1]){
                    char tmp = s[j];
                    s[j] =s[j+1];
                    s[j+1]=tmp;
                }
            }
        }
    }
};

复杂度和稳定性

时间:O(n2),因为循环遍历两次,所以n2
空间:O(1),原地交换,没有使用额外的空间
稳定性:稳定的,因为如果两者相等,不会交换顺序

堆排序

将数组转成一个完全二叉树,一个节点的值比左右两个孩子都要大;
这样最大值就是根节点,去除根节点后,剩下的树就不符合堆的特性了,所以如果还能让第二大小的点移到根节点,那么就实现排序问题;

步骤

  1. 将被排序的数组行成一个完全二叉树
  2. 将该完全二叉树形成一个堆
  3. 排序,即陆续将根节点移除,并接着将剩下的二叉树形成一个堆

代码

class Solution {
public:
    bool isAnagram(string s, string t) {
        if(s.size() != t.size()){
            return false;
        }

        char* p_s = (char*)s.c_str();
        char* p_t = (char*)t.c_str();

        heapSort(p_s, s.size());
        heapSort(p_t, t.size());

        printf("%s, %s\n", p_s, p_t);
        for(int i=0;i<s.size();i++){
            if(p_s[i] != p_t[i]){
                return false;
            }
        }
        return true;
    }

    void heapSort(char* s, int s_len){
        //init heap
        for(int i=s_len/2-1; i>=0; i--){
            heapify(s, s_len, i);
        }

        //sort
        while(s_len>0){
            char tmp = s[0];
            s[0] = s[s_len-1];
            s[s_len-1]=tmp;
            s_len--;
            heapify(s, s_len, 0);
        }
    }

    void heapify(char* s, int s_len, int i){
        int max = i;
        int left_child = i*2 +1;
        int right_child = i*2 +2;

        if(left_child<s_len && s[max] < s[left_child]){
            max = left_child;
        }
        if(right_child<s_len && s[max] < s[right_child]){
            max = right_child;
        }

        if(max != i){
            char tmp = s[i];
            s[i] = s[max];
            s[max] = tmp;
            heapify(s, s_len, max);
        }
    }
};

注意

假设数组长度是n,当前节点是i,那么
左孩子索引 1 * 2 +1;
右孩子索引 1 * 2 + 2;
父节点:(i-1)/2
最后一个叶子:n-1
最有一个非叶子节点:(n-1-1)/2=n/2-1

复杂度和稳定性

时间复杂度:O(nlgn)
稳定性:不稳定,因为通过调换,可能会将相等的两个次序打乱

快速排序

步骤

这是一个分治思想,先找一个中位数,然后小于中位数的全都放在左边,大于中位数的全都放在右边;
然后递归执行中位数左边和右边;

注意事项

中位数最好不要是最大值和最小值,因为如果是最大或者最小的话,会导致其实没有分治,这样复杂度和冒泡一样。

代码

class Solution {
public:
    bool isAnagram(string s, string t) {
        if(s.size() != t.size()){
            return false;
        }

        char* p_s = (char*)s.c_str();
        char* p_t = (char*)t.c_str();

        quickSort(p_s, s.size());
        quickSort(p_t, t.size());

        printf("%s, %s\n", p_s, p_t);
        for(int i=0;i<s.size();i++){
            if(p_s[i] != p_t[i]){
                return false;
            }
        }
        return true;
    }

    int getPivot(char* s, int left, int right){
        int middle = (left + right)/2;
        if(s[left] < s[middle] && s[middle] < s[right]){
            return middle;
        }else if(s[left] > s[middle] && s[middle] > s[right]){
            return middle;
        }else if(s[middle] > s[left] && s[left] > s[right]){
            return left;
        }else if(s[middle] < s[left] && s[left] < s[right]){
            return left;
        }else if(s[middle] > s[right] && s[right] > s[left]){
            return right;
        }else if(s[middle] < s[right] && s[right] < s[left]){
            return right;
        }else{
            return middle;
        }
    }

    void quickSort(char* s, int begin, int end){
        if(begin >= end){
            return;
        }

        int pivot = getPivot(s, begin, end);
        swap(s, pivot, begin);
        pivot=begin;
        int low = begin + 1;
        int high  = end;

        bool high_to_low = true;
        while(high>=low){
            if(high_to_low){
                if(s[high]<=s[pivot]){
                    swap(s, high, pivot);
                    pivot=high;
                    high_to_low=false;
                }
                high--;
            }else{
                if(s[low]>=s[pivot]){
                    swap(s, low, pivot);
                    pivot=low;
                    high_to_low=true;
                }
                low++;
            }
        }

        quickSort(s, begin, pivot-1);
        quickSort(s, pivot+1, end);
    }

    void quickSort(char* s, int s_len){
        quickSort(s, 0, s_len-1);
    }

    void swap(char* s, int a, int b){
        char tmp = s[a];
        s[a] = s[b];
        s[b]= tmp;
    }
};

复杂度和稳定性

时间复杂度:O(nlgn)
稳定性:不稳定,因为通过调换,可能会将相等的两个次序打乱

计数排序

由于被排序的元素是小写字母,是26个,数量并不多,可以该问题可以使用计数排序,这样只要记下每个字母有多少,这样就能判断两个字符串是否一样

代码

class Solution {
public:
    bool isAnagram(string s, string t) {
        if(s.size() != t.size()){
            return false;
        }

        char* p_s = (char*)s.c_str();
        char* p_t = (char*)t.c_str();

        countSort(p_s, s.size());
        countSort(p_t, t.size());

        printf("%s, %s\n", p_s, p_t);
        for(int i=0;i<s.size();i++){
            if(p_s[i] != p_t[i]){
                return false;
            }
        }
        return true;
    }

    void countSort(char* s, int s_len){
        int alphas[26] = {0};
        for(int i = 0; i < s_len; i++){
            alphas[s[i] - 'a']++;
        }

        int index = 0;
        for(int i = 0; i<26;i++){
            for(int j=0;j<alphas[i];j++){
                s[index] = i + 'a';
                index++;
            }
        }
    }

    void swap(char* s, int a, int b){
        char tmp = s[a];
        s[a] = s[b];
        s[b]= tmp;
    }
};

复杂度和稳定性

时间复杂度:O(n)
空间复杂度:O(n),空间换时间
稳定性:稳定,因为通过调换,可能会将相等的两个次序打乱

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351

推荐阅读更多精彩内容

  • 快排上图中空间复杂度数据错误,应该是O(log n)。 插入,堆,归并,快排 n表示数据规模,k表示桶的个数。n:...
    hadoop_a9bb阅读 1,609评论 2 36
  • 总结一下常见的排序算法。 排序分内排序和外排序。内排序:指在排序期间数据对象全部存放在内存的排序。外排序:指在排序...
    jiangliang阅读 1,336评论 0 1
  • 本文首发于我的个人博客:尾尾部落 排序算法是最经典的算法知识。因为其实现代码短,应该广,在面试中经常会问到排序算法...
    繁著阅读 4,572评论 3 119
  • 1 初级排序算法 排序算法关注的主要是重新排列数组元素,其中每个元素都有一个主键。排序算法是将所有元素主键按某种方...
    深度沉迷学习阅读 1,400评论 0 1
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 将一个记录插入到已排序好...
    依依玖玥阅读 1,246评论 0 2