2020-07-03 二分查找揍堰,二叉樹鹏浅,位運(yùn)算嗅义,隊列

53-I 在排序數(shù)組中查找數(shù)字 I

利用二分查找法,可以定位到第一個或者最后一個查找元素隐砸。
查找第一個時之碗,如果中間元素小于或大于查找元素,都可以將區(qū)間縮小一半季希;而中間元素等于查找元素時褪那,需要判斷中間元素是不是第一個出現(xiàn)的元素,判斷方式為查看前一個元素式塌,如果前一個元素等于查找元素博敬,第一個元素則出現(xiàn)在前一半?yún)^(qū)間中;如果前一個元素不等于查找元素峰尝,第一個元素就是當(dāng)前元素偏窝,可以返回。
查找最后一個出現(xiàn)的元素位置也是類似的做法境析。

class Solution {
public:
    int search_first(vector<int> &nums, int target, int left, int right){
        if(left > right)
            return -1;
        int mid = left + (right - left) / 2;
        if(nums[mid] > target)
            return search_first(nums, target, left, mid - 1);
        if(nums[mid] < target)
            return search_first(nums, target, mid + 1, right);
        // nums[mid] == target
        // 這里利用了短路的做法
        if(mid == left || nums[mid - 1] != target)
            return mid;
        return search_first(nums, target, left, mid - 1);
    }
    int search_last(vector<int> &nums, int target, int left, int right){
        if(left > right)
            return -1;
        int mid = left + (right - left) / 2;
        if(nums[mid] > target)
            return search_last(nums, target, left, mid - 1);
        if(nums[mid] < target)
            return search_last(nums, target, mid + 1, right);
        // nums[mid] == target
        if(mid == right || nums[mid + 1] != target)
            return mid;
        return search_last(nums, target, mid + 1, right);
    }
    int search(vector<int>& nums, int target) {
        int first = search_first(nums, target, 0, nums.size() - 1);
        if(first < 0)
            return 0;
        int last = search_last(nums, target, 0, nums.size() - 1);
        return last - first + 1;
    }
};

53 - II. 0~n-1中缺失的數(shù)字

二分查找法囚枪,如果中間數(shù)字等于下標(biāo)數(shù),缺失的數(shù)字就在右半邊劳淆;否則,查看左邊的數(shù)字是不是等于下標(biāo)默赂,等于的話沛鸵,中間下標(biāo)就是缺失的數(shù)字,否則在左半邊缆八。
實現(xiàn)用了遞歸和迭代兩種實現(xiàn)方法:
迭代

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        int left = 0, right = nums.size();
        int mid, ret;
        while(left < right){
            mid = left + (right - left) / 2;
            if(nums[mid] == mid){
                left = mid + 1;
            }
            else{
                if(mid == 0 || (mid > 0 && nums[mid - 1] == mid - 1))
                    return mid;
                else
                    right = mid;
            }
        }
        return left;
    }
};

遞歸

public:
    int binary_search(vector<int>& nums, int left, int right){
        if(left >= right)
            return left;
        int mid = left + (right - left) / 2;
        if(nums[mid] == mid)
            return binary_search(nums, mid + 1, right);
        if(mid == 0 || (mid > 0 && nums[mid - 1] == mid - 1))
            return mid;
        return binary_search(nums, left, mid);
    }
    int missingNumber(vector<int>& nums) {
        return binary_search(nums, 0, nums.size());
    }
};

54 二叉搜索樹的第k大節(jié)點

二叉搜索樹的中序遍歷是有序的曲掰。因此對二叉搜索樹進(jìn)行逆中序遍歷,返回值為TreeNode指針奈辰,未找到第k個節(jié)點之前栏妖,返回空指針,找到后返回該節(jié)點指針奖恰。每次右孩子遍歷完吊趾,將k減一,k減到1時瑟啃,找到了第k大的節(jié)點论泛。
這個題目的代碼邏輯比較難寫,需要重點學(xué)習(xí)下蛹屿。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* kthLargestCore(TreeNode* root, int &k){
        if(root == nullptr)
            return nullptr;
        TreeNode* target = kthLargestCore(root -> right, k);
        if(target == nullptr){
            if(k == 1)
                target = root;
            k--;
        }
        if(target == nullptr)
            target = kthLargestCore(root -> left, k);
        return target;
    }
    int kthLargest(TreeNode* root, int k) {
        TreeNode* target = kthLargestCore(root, k);
        return target -> val;
    }
};

55-II 平衡二叉樹

該問題可以用二叉樹的后序遍歷解決屁奏,首先判斷左右子樹分別是否平衡,如果左右子樹平衡错负,再根據(jù)左右子樹的高度坟瓢,判斷該樹是否平衡勇边,并且返回樹高度。這樣只需要遍歷一次即可折联。
另一個技巧粒褒,如果有多個需要返回的值,可以將其中某些值的引用作為參數(shù)傳回來崭庸。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isBalanced_Depth(TreeNode* root, int &depth){
        if(root == nullptr){
            depth = 0;
            return true;
        }
        int left_depth = 0, right_depth = 0;
        if(isBalanced_Depth(root -> left, left_depth) && isBalanced_Depth(root -> right, right_depth)){
            if(abs(left_depth - right_depth) <= 1){
                depth = max(left_depth, right_depth) + 1;
                return true;
            }
            else return false;
        }
        else return false;
    }
    bool isBalanced(TreeNode* root) {
        int depth = 0;
        return isBalanced_Depth(root, depth);
    }
};

56-I 數(shù)組中只出現(xiàn)一次的兩個數(shù)字

這個題目有點難怀浆,如果只有一個數(shù)字只出現(xiàn)一次,那么我們可以利用同一個數(shù)異或兩次是0怕享,將所有數(shù)字進(jìn)行異或操作执赡,最后的結(jié)果就是只出現(xiàn)一次的數(shù)字。
如果有兩個數(shù)字只出現(xiàn)一次函筋,那么將所有數(shù)字異或一次沙合,得到的結(jié)果是這兩個數(shù)字的異或結(jié)果,這個數(shù)字一定不為0跌帐。找到這個數(shù)字中出現(xiàn)1的某一位首懈,則這兩個只出現(xiàn)一次的數(shù)中,一個是這一位等于1谨敛,一個是不等于1.通過這一位是否為1究履,可以將這兩個數(shù)字分到兩個數(shù)組中,之后脸狸,分別在這兩個數(shù)組中進(jìn)行異或最仑,就可以得到這兩個數(shù)字。

class Solution {
public:
    vector<int> singleNumbers(vector<int>& nums) {
        int EORresult = 0;
        for(int i = 0; i < nums.size(); i++)
            EORresult ^= nums[i];
        // find first 1
        int k = 0;
        while(EORresult % 2 == 0){
            EORresult = EORresult >> 1;
            k++;
        }
        int check_mod = 1 << k;
        // divide nums into two parts
        int num1 = 0, num2 = 0;
        for(int i = 0; i < nums.size(); i++){
            if(nums[i] & check_mod)
                num1 ^= nums[i];
            else
                num2 ^= nums[i];
        }
        vector<int> ret = {num1, num2};
        return ret;
    }
};

56-II 數(shù)組中唯一只出現(xiàn)一次的數(shù)字

其他數(shù)字都出現(xiàn)3次炊甲,因此泥彤,這個題目就不能用異或來做了,但還是可以用位運(yùn)算的思路卿啡。每個數(shù)字的每一位相加三次吟吝,這一位的和一定可以整除3.那么將所有數(shù)字的每一位求和,如果某一位的和可以整除3颈娜,那么這個只出現(xiàn)一次的數(shù)字在這一位上一定為0剑逃,否則為1。

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int bit_sum[32] = {0};
        for(int i = 0; i < nums.size(); i++){
            int tmp = nums[i], j = 0;
            while(tmp){
                if(tmp & 1)
                    bit_sum[j]++;
                tmp = tmp >> 1;
                j++;
            }
        }
        for(int i = 0; i < 32; i++)
            bit_sum[i] = bit_sum[i] % 3;
        int num = 0;
        for(int i = 31; i >= 0; i--)
            num = (num << 1) + bit_sum[i];
        return num;
    }
};

57-II 和為s的連續(xù)正數(shù)序列

還是用雙指針揭鳞,left和right炕贵,當(dāng)前和小于target時,right++野崇,大雨target時称开,left++,等于時,記錄下當(dāng)前的序列鳖轰。

class Solution {
public:
    vector<vector<int>> findContinuousSequence(int target) {
        vector<vector<int>> ret;
        int left = 1, right = 2, sum = 3;
        while(2 * left < target){
            if(sum == target){
                vector<int> tmp;
                for(int i = left; i <= right; i++)
                    tmp.push_back(i);
                ret.push_back(tmp);
            }
            if(sum <= target){
                right++;
                sum += right;
            }
            else{
                sum -= left;
                left++;
            }
        }
        return ret;
    }
};

58 翻轉(zhuǎn)單詞順序

先翻轉(zhuǎn)整句話清酥,再翻轉(zhuǎn)每個單詞。比較麻煩的就是空格的處理蕴侣,所以開辟了額外空間焰轻,如果空格沒問題,就可以原地翻轉(zhuǎn)了昆雀。

class Solution {
public:
    string reverse_string(string s, int begin, int end){
        string rev_s = "";
        for(int i = end; i >= begin; i--)
            rev_s += s[i];
        return rev_s;
    }
    string reverseWords(string s) {
        // remove extra spaces
        s = reverse_string(s, 0, s.size() - 1);
        string ret_s = "";
        int begin = 0, end = 0, str_len = s.size();
        while(end < str_len){
            while(begin < str_len && s[begin] == ' ')
                begin++;
            if(begin == str_len)
                break;
            end = begin;
            while(end < str_len && s[end] != ' ')
                end++;
            if(ret_s.size())
                ret_s += ' ';
            ret_s += reverse_string(s, begin, end - 1);
            begin = end;
        }
        return ret_s;
    }
};

58-II 左旋轉(zhuǎn)字符串

還是兩次旋轉(zhuǎn)辱志,第一次旋轉(zhuǎn)0-k,k-strlen狞膘,第二次旋轉(zhuǎn)整個字符串揩懒。

class Solution {
public:
    void reverse_string(string &s, int begin, int end){
        while(begin < end){
            char tmp = s[begin];
            s[begin] = s[end];
            s[end] = tmp;
            begin++;
            end--;
        }
    }
    string reverseLeftWords(string s, int n) {
        reverse_string(s, 0, n - 1);
        reverse_string(s, n, s.size() - 1);
        reverse_string(s, 0, s.size() - 1);
        return s;
    }
};

59-I 滑動窗口的最大值

用雙向隊列,存放所有可能成為滑動窗口最大值的元素的下標(biāo)挽封。如果當(dāng)前隊列中的每個元素小于新加進(jìn)來的元素已球,那么這個元素就不可能成為后面的滑動窗口的最大值,應(yīng)該出隊列辅愿,此時是從隊尾出隊列智亮。另一方面,如果當(dāng)前隊列中某個元素的下標(biāo)已經(jīng)在滑動窗口之外点待,那么這個元素也應(yīng)該出隊列阔蛉,此時從隊首出隊列。每次癞埠,當(dāng)前最大元素就在隊頭馍忽。

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        deque<int> binary_queue;
        vector<int> maxes;
        for(int i = 0; i < nums.size(); i++){
            while(binary_queue.size() && binary_queue.front() + k <= i)
                binary_queue.pop_front();
            while(binary_queue.size() && nums[binary_queue.back()] < nums[i])
                binary_queue.pop_back();
            binary_queue.push_back(i);
            if(i >= k - 1)
                maxes.push_back(nums[binary_queue.front()]);
        }
        return maxes;
    }
};

59-II 隊列的最大值

實現(xiàn)一個最大隊列,pop燕差,push,max都是常數(shù)時間坝冕。跟滑動窗口類似徒探,用一個雙向隊列存放當(dāng)前最大值。每次push的時候喂窟,雙向隊列中存入可能成為最大值的值测暗,也就是說,如果隊列中的某些元素比push進(jìn)來的元素小磨澡,那么他們不可能成為最大值了碗啄,就應(yīng)該先出隊列。pop時稳摄,需要判斷一下當(dāng)前隊頭的元素是否要pop的元素稚字,如果是,就出隊列。
一個需要注意的地方是如果隊列中有相同的元素胆描,這兩個元素都會進(jìn)入雙向隊列瘫想,這樣pop的時候不會出錯。

class MaxQueue {
public:
    MaxQueue():q_size(0){}
    
    int max_value() {
        if(q_size == 0)
            return -1;
        return max_q.front();
    }
    
    void push_back(int value) {
        q.push(value);
        while(!max_q.empty() && max_q.back() < value)
            max_q.pop_back();
        max_q.push_back(value);
        q_size++;
    }
    
    int pop_front() {
        if(q_size == 0)
            return -1;
        int ret = q.front();
        q.pop();
        if(ret == max_q.front())
            max_q.pop_front();
        q_size--;
        return ret;
    }
private:
    deque<int> max_q;
    queue<int> q;
    int q_size;
};
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末昌讲,一起剝皮案震驚了整個濱河市国夜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌短绸,老刑警劉巖车吹,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異醋闭,居然都是意外死亡窄驹,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進(jìn)店門目尖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來馒吴,“玉大人,你說我怎么就攤上這事瑟曲∫粒” “怎么了?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵洞拨,是天一觀的道長扯罐。 經(jīng)常有香客問我,道長烦衣,這世上最難降的妖魔是什么歹河? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮花吟,結(jié)果婚禮上秸歧,老公的妹妹穿的比我還像新娘。我一直安慰自己衅澈,他們只是感情好键菱,可當(dāng)我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著今布,像睡著了一般经备。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上部默,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天侵蒙,我揣著相機(jī)與錄音,去河邊找鬼傅蹂。 笑死纷闺,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播急但,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼澎媒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了波桩?” 一聲冷哼從身側(cè)響起戒努,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎镐躲,沒想到半個月后储玫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡萤皂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年撒穷,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片裆熙。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡端礼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出入录,到底是詐尸還是另有隱情蛤奥,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布僚稿,位于F島的核電站凡桥,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蚀同。R本人自食惡果不足惜缅刽,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蠢络。 院中可真熱鬧衰猛,春花似錦、人聲如沸刹孔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芦疏。三九已至,卻和暖如春微姊,著一層夾襖步出監(jiān)牢的瞬間酸茴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工兢交, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留薪捍,地道東北人。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像酪穿,于是被迫代替她去往敵國和親凳干。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,440評論 2 359