2019-01-26 第二天(#189, #41, #299)

#189 Rotate Array

初见 (O(n^2)复杂度)

我觉得这个应该算是brute force。先用back()获取最后一个元素,用erase()擦除最后一个元素,再在数组头用insert()插入该元素。

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int size = nums.size();
        k %= size;
        for(int it = 0; it < k; it++){
            int temp = nums.back();
            nums.erase(nums.end()-1);
            nums.insert(nums.begin(), temp);
        }
    }
};

问题主要在insert()这个函数在数组头插入的话时间复杂度是O(n),那这么下来整体的时间复杂度就是O(n^2)。
我以为这个会超过时间限制,但是居然也打败了31.91%的人,可喜可贺可喜可贺。

辅助数组 (O(n)空间复杂度)

这个算是比较直观的解法了,具体而言就是把需要rotate的元素移出来存到另一个数组ans里,然后再把剩余元素push到ans中。这种方法出来的rotate元素会和所需要的刚好相反,可以翻转一下。

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int size = nums.size();
        k %= size;
        vector<int> ans;
        for(int it = 0; it < k; it++){
            int temp = nums.back();
            ans.push_back(temp);
            nums.erase(nums.end()-1);
        }
        
        reverse(ans.begin(), ans.end());
        
        for(int ind = 0; ind < nums.size(); ind++){
            ans.push_back(nums.at(ind));
        }
        
        nums = ans;
    }
};

这方法把时间复杂度降到了O(n),但也有个缺点是它有O(n)的空间复杂度,还不如初见的那个brute force版本。

三次翻转 (O(1)空间复杂度)

这个方法说实话我自己肯定想不出来,但是在网站的solution里面有,去YouTube看了看也是主流的方法之一,权当背下来吧。
这个方法说白了就是把整个数组分成两部分:需要rotate“走”的部分,和剩余的部分。
举个例子:
数组[1 2 3 4 5 6 7],k = 3
那这个地方需要rotate走的就是[5 6 7]这一块,剩下的就是[1 2 3 4];
先把所有的元素翻转过来:[7 6 5 4 3 2 1]
然后翻转rotate走的部分:[5 6 7 4 3 2 1]
最后翻转剩下部分:[5 6 7 1 2 3 4]
三次翻转就可以完成这个rotate的过程。
代码实现:

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int size = nums.size();
        k %= size;
      
        reverse(nums.begin(), nums.end());
        reverse(nums.begin(), nums.begin()+k);
        reverse(nums.begin()+k, nums.end());
        
        
    }
};

要注意的是,reverse()这个函数接受的第二个参数应该指向需要翻转元素的后一个位置
这个算法的时间复杂度为O(n),空间复杂度为O(1)(不需要占用额外空间)。

#41 First Missing Positive

题目地址:https://leetcode.com/problems/first-missing-positive/
这个题显然可以用sorting解决,但是题目要求O(n)的复杂度,就不放上来了。

辅助数组(O(n)空间复杂度)

解法的核心思想是"Put its number in its right place"
对于这道题来说,不需要考虑负数,也不需要考虑值大于数组长度的数(因为要找的是“最小缺失正数”,如果数组内出现了不连续,那么最小缺失正数的值必然小于数组长度)那么我只需要建立一个新的数组,然后把元素放到对应值作为下标的位置就好。
例如说nums[3] = 5,那我就让新数组ans[4]=5。
这样之后排出来的新数组算是部分排好序的,那再对这个新数组遍历一遍就能知道答案。

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int size = nums.size();
        vector<int> ans(size, 0);
        
        for(auto it = nums.begin(); it != nums.end(); it++){
            if(*it <= size && *it > 0)
                ans.at(*it-1) = *it;
        }
        
        int smallest = 1;
        for(auto it = ans.begin(); it != ans.end(); it++){
            if(*it == smallest)
                smallest++;
        }
        
        return smallest;
    }
};

这个解法的时间复杂度为O(n),空间复杂度为O(n)。

交换(O(1)空间复杂度)

这题的要求其实是空间复杂度为常数。那么如果不能建立辅助数组,要重新对这个数组部分排序就只能用交换元素的方法了。
交换一次并不能达到效果,只要当前下标对应的值不是所需要的值,就必须一直交换。举个例子:
数组[5 3 1 2 4]。
第一次交换:
[4 3 1 2 5]
此时nums(0)处的数字依然不是1(换言之,这个地方的元素并不“对”),我们要一直交换到它为1为止:
[2 3 1 4 5]
继续:
[3 2 1 4 5]
[1 2 3 4 5]
这就完成了nums(0)处的交换,之后对nums(1)到nums(4)上都进行同样的判断。但由于此时整个数组已经是完全排序好了,之后的下标处就不需要再交换了。
代码如下:

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int size = nums.size();
        
        for(auto it = nums.begin(); it != nums.end();){
            if(*it <= size && *it > 0 && *it == nums.at(*it-1))
                it++;
            else if(*it <= size && *it > 0)
                iter_swap(it, nums.begin()+*it-1);
            else{
                *it = 0;
                it++;
            }
        }
        
        int smallest = 1;
        for(auto it = nums.begin(); it != nums.end(); it++){
            if(*it == smallest)
                smallest++;
        }
        
        return smallest;
    }
};

理论上来说这个方法应该是比用辅助数组的方法慢的(时间复杂度严格说应该是O(3n),辅助数组是O(2n)),实际上leetcode的运行结果也是如此。但是O(3n)=O(2n)=O(n),再加上O(1)的空间复杂度,这个算法也可以说是最优解之一。

#299 Bulls and Cows

题目地址:https://leetcode.com/problems/bulls-and-cows/

初见(Hash Table)

既然输入只有0到9一共10个数字,那不用Hash Table做简直是天理难容。把除了bull之外的情况都统计下来,只要双方数字都不为0的情况下就代表出现了cow的情况,这时候取其中较小的计数作为cow。

class Solution {
public:
    string getHint(string secret, string guess) {
        vector<int> nums(10, 0);
        vector<int> numbulls(10, 0);
        int size = secret.size();
        int bulls = 0;
        int cows = 0;
        for(int ind = 0; ind < size; ind++){
            if(secret.at(ind) == guess.at(ind))
                bulls++;
            else{
                int digit = guess.at(ind) - '0';
                int digitbull = secret.at(ind) - '0';
                nums.at(digit)++;
                numbulls.at(digitbull)++;
            }
            
        }
        for(int ind = 0; ind < nums.size(); ind++){
            if(nums.at(ind) > 0 && numbulls.at(ind) > 0){
                cows += min(nums.at(ind), numbulls.at(ind));
            }
        }
        
        string answer;
        answer = to_string(bulls) + "A" + to_string(cows) + "B";
        return answer;
    }
};

实际上只需要遍历数组一次(第二个for循环遍历的是长度为10的定长数组),时间复杂度为O(n)。

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

推荐阅读更多精彩内容