LeetCode_Nov_4th_Week

Posted KuoGavin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode_Nov_4th_Week相关的知识,希望对你有一定的参考价值。

November 22nd : 384. 打乱数组
November 23rd : 859. 亲密字符串
November 24th : 423. 从英文中重建数字


November 22nd : 384. 打乱数组

① 依次从待选数字(要打乱的数组的数字)中随机选出一个,然后放入 s h u f f l e shuffle shuffle 数组的当前位置上,位置再逐次后移,同时把所选出的数字从要打乱的数组中删掉,这样遍历操作一遍即可得到等概率的打乱数组。对于原数组中的数字,移动到第 i i i 个位置的概率是 1 n \\frac1n n1

对于删掉要打乱的数组中所随机选取的元素,可采用链表的数据结构,搭配哈希表, O ( 1 ) O(1) O(1) 时间复杂度查找和删除数字。

② ①的思路可以经过整理变形,先把要打乱的数组复制为 s h u f f l e shuffle shuffle 数组,再把 s h u f f l e shuffle shuffle 数组第 i i i 个数字换至数组中的一个随机位置。也即是从排列的方式思考一下从 n ! n! n! 中选随机数的方案, n ! = n ∗ ( n − 1 ) ! n! = n * (n-1)! n!=n(n1)! 这里的 n n n 就是你先挑选出第一个元素的种类数;然后 ( n − 1 ) ! (n-1)! (n1)! 就是对其他元素的排列。所以我们要选一种洗牌方案,就可以先等概率的从 n n n 个元素中挑选一个作为第一个元素;然后再对剩下的 ( n − 1 ) (n-1) (n1) 个元素作类似的选择。这样就相当于把 n ! n! n! 分成 n n n 段,先选择其中一段,里面有 ( n − 1 ) ! (n-1)! (n1)! 个元素,我们把这 ( n − 1 ) ! (n-1)! (n1)! 个情况分成 ( n − 1 ) (n-1) (n1) 段,再随机选一个,以此类推。 这样的策略是可以做到从 ( n − 1 ) ! (n-1)! (n1)! 中随机选数的。

//version 2②
class Solution 
public:
    Solution(vector<int>& nums) 
        Elements = nums;
    
    
    vector<int> reset() 
        return Elements;
    
    
    vector<int> shuffle() 
        vector<int> vShuffle = Elements;
        for(int i = 1; i < vShuffle.size(); ++i) 
            int r = rand() % (i + 1);
            swap(vShuffle[r], vShuffle[i]);
        
        return vShuffle;
    
private:
    vector<int> Elements;
;

November 23rd : 859. 亲密字符串

满足以下两个条件,两字符串互为亲密字符串:
① 两字符串字符频次相同(可以使用异或的方法,在 O ( n ) O(n) O(n)时间复杂度下计算频次是否相同,但是步骤②还需要字符的频次数目,所以使用数组计数方法);
② 有两个位置两字符串对应的字符不一致,或都对应一致但是有字符的频次大于等于 2 2 2

时间复杂度 O ( n + C ) O(n+C) O(n+C),空间复杂度 O ( C ) O(C) O(C);根据数据规模, O ( n 2 ) O(n^2) O(n2)的计算量在 4 ∗ 1 0 8 4*10^8 4108,要超时,暴力方法不能通过。

class Solution 
public:
    bool buddyStrings(string s, string goal) 
        if(s.size() != goal.size()) return false;
        vector<int> cnt1 = vector<int>(26, 0);
        vector<int> cnt2 = vector<int>(26, 0);
        int chLocDiff = 0; //同一位置字符不同的数目
        for(int i = 0; i < s.size(); ++i) 
            cnt1[s[i] - 'a']++;
            cnt2[goal[i] - 'a']++;
            if(s[i] != goal[i]) chLocDiff++;
        
        bool hasSame = false; //是否有频次大于2的字符
        for(int i = 0; i < 26; ++i) 
        	//同一字符频次不同,直接返回假
            if(cnt1[i] != cnt2[i]) return false;
            if(cnt1[i] > 1) hasSame = true;
        
        //频次相同,不同数目为2,
        //或不同数目为0且有频次大于2字符则为真
        return chLocDiff == 2 || (hasSame && chLocDiff == 0);
    
;

November 24th : 423. 从英文中重建数字

统计各个字母在不同数字当中出现的频次,一些特定的数字对应的有特定的唯一的字母,根据唯一字母数先确定这些特定数字个数,再进一步推断出剩余数字的个数。

class Solution 
public:
    string originalDigits(string s) 
        int dict[26] = 0;
        int nums[10] = 0;
        for(int i = 0; i < s.size(); ++i) dict[s[i]-'a']++;
        nums[0] = dict['z'-'a']; //zero,只有0含字母z
        nums[2] = dict['w'-'a']; //two,只有2含字母w
        nums[4] = dict['u'-'a']; //four,只有4含字母u
        nums[6] = dict['x'-'a']; //six,只有6含字母x
        nums[8] = dict['g'-'a']; //eight,只有8含字母g
        nums[3] = dict['h'-'a'] - nums[8]; //含h的只有3,8
        nums[5] = dict['f'-'a'] - nums[4]; //含f的只有4,5
        nums[7] = dict['v'-'a'] - nums[5]; //含v的只有5,7
        nums[9] = dict['i'-'a'] - nums[5] - nums[6] - nums[8]; //含i的只有5,6,8,9,且均只含一个
        nums[1] = dict['o'-'a'] - nums[0] - nums[2] - nums[4]; //含o的只有0,1,2,4,且均只含一个
        string ret = "";
        for(int i = 0; i < 10; ++i) 
            for(int j = 0; j < nums[i]; ++j) 
                ret += to_string(i);
        return ret;
    
;

以上是关于LeetCode_Nov_4th_Week的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode_Nov_5th_Week

LeetCode_Nov_3rd_Week

LeetCode_Nov_1st_Week

LeetCode_Nov_2nd_Week

这些 C++ 代码片段有啥作用?

[AndroidStudio]_[初级]_[配置自动完成的代码片段]