【算法設計作業】week14

【算法設計作業】week14

給出了第33、34,35、36、38、39、41、45題的解析


33. Search in Rotated Sorted Array

題目來源:https://leetcode.com/problems/search-in-rotated-sorted-array/description/

題意

給出一個初始升序序列,經過一個(注:一個)“rotation”之後的序列。例如0 1 2 4 5 6 7 經過一次”rotation”可以變成4 5 6 7 0 1 2
要求在這個rotation過的序列中尋找給定元素target的index。

思路

經過rotation後,必定只有一半是升序的,而另一半是降序的。判斷出要哪一半後,就可以對這一半進行二分搜索。

參考代碼

http://www.cnblogs.com/grandyang/p/4325648.html


34. Search for a Range

題目來源https://leetcode.com/problems/search-for-a-range/description/

題意

給出一個有序數列,求出給定target的範圍,用左閉右閉區間表示。如果不存在,則返回[-1, -1]

思路

實現兩個函數,分別是upper_bound求上界,lower_bound求下界,調用這兩個函數,即得出結果。

1.lower_bound

首先看int lower_bound(vector<int>& nums, int x, int y, int v),在這個函數中,nums 是有序數列,搜索範圍是[x, y)注!左閉右開區間!但返回區間是左閉右閉區間,因爲可能返回最後一個元素的後一個位置,這就是待插入位置),v 是所求的搜索目標。
這個函數是這樣的:

 int lower_bound(vector<int>& nums, int x, int y, int v) {
        int m;
        while(x < y) {
            m = x + (y - x) / 2;
            if(nums[m] >= v) y = m;
            else x = m + 1;
        }
        return x;
    }

我們用二分搜索的思想,首先求出xy 的中值,m
記住我們此時求的是下界,並且搜索區間是左閉右開的,返回區間是左閉右閉的,然後有下面這三種情況:

  • nums[m]=v 至少已經找到一個了,左邊可能還有,因而區間變爲[x,m]
  • nums[m]>v,所求位置不可能在m後面,但有可能在m上,區間變爲[x,m]
  • nums[m]<v, m 和前面的都不可行,區間變爲 [m+1, y]
    而頭兩種情況可以合併。

2.upper_bound

lower_bound 原理類似。

參考代碼

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        vector<int> ans;
        int low = lower_bound(nums, 0, nums.size(), target);
        int high = upper_bound(nums, 0, nums.size(), target)-1;
        if (low > high) {
            ans.push_back(-1);
            ans.push_back(-1);
        } else {
            ans.push_back(low);
            ans.push_back(high);
        }
        return ans;
    }

    int lower_bound(vector<int>& nums, int x, int y, int v) {
        int m;
        while(x < y) {
            m = x + (y - x) / 2;
            if(nums[m] >= v) y = m;
            else x = m + 1;
        }
        return x;
    }

    int upper_bound(vector<int>& nums, int x, int y, int v) {
        int m;
        while(x < y) {
            m = x + (y - x) / 2;
            if(nums[m] <= v) x = m+1;
            else y = m;
        }
        return x;
    }
};

35. Search Insert Position

來源:https://leetcode.com/problems/search-insert-position/description/

題意

給出一個序列,返回target的位置。如果不存在,則返回target應插入的位置。

思路

和第34題的upper_bound一摸一樣

參考代碼

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int x = 0, y = nums.size();
        int m;
        while(x < y){
            m = x + (y-x)/2;
            if(nums[m] >= target) y = m;
            else x = m + 1;
        }
        return x;
    }
};

36. Valid Sudoku

來源https://leetcode.com/problems/valid-sudoku/description/

題意

給出一個部分的數獨,問已經填的數字是否符合數獨規則。

思路

很簡單,只要分別判斷每一行,每一列,每個九宮格是否出現重複數字即可。

參考代碼

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        for(int i = 0; i < 9; i++) {
            if (!(isColValid(board, i) && isRowValid(board, i) && isSquareValid(board, i/3, i%3))) {
                return false;
            }
        }
        return true;
    }

    bool isColValid(vector<vector<char>>& board, int col) {
        bool seen[10];
        for(int i = 0; i < 10; i++) seen[i] = false;
        for(int i = 0; i < 9; i++) {
            if(board[i][col] != '.') {
                int num = board[i][col] - '0';
                if(seen[num] == false) {
                    seen[num] = true;
                } else {
                    return false;
                }
            } 
        }
        return true;
    }

    bool isRowValid(vector<vector<char>>& board, int row) {
        bool seen[10];
        for(int i = 0; i < 10; i++) seen[i] = false;
        for(int i = 0; i < 9; i++) {
            if(board[row][i] != '.') {
                int num = board[row][i] - '0';
                if(seen[num] == false) {
                    seen[num] = true;
                } else {
                    return false;
                }
            } 
        }
        return true;
    }

    bool isSquareValid(vector<vector<char>>& board, int x, int y) {
        x = x * 3;
        y = y * 3;
        bool seen[10];
        for(int i = 0; i < 10; i++) seen[i] = false;
        for(int i = 0; i < 3; i++) {
            for(int j = 0; j < 3; j++) {
                if(board[x+i][y+j] != '.') {
                    int num = board[x+i][y+j] - '0';
                    if(seen[num] == false) {
                        seen[num] = true;
                    } else {
                        return false;
                    }
                } 
            }
        }
        return true;
    }

};

38. Count and Say

題目來源:https://leetcode.com/problems/count-and-say/description/

題意

給出序列,如下:

1.     1
2.     11
3.     21
4.     1211
5.     111221

要求返回第n條序列。第n條序列是對第n-1條序列的讀法,如n=2的序列就是對n=1序列的讀,“1個1”,即11。11讀作“2個1”,因而n=3是“21”.

思路

很簡單,按照題意遞歸就是了。

代碼

class Solution {
public:
    string countAndSay( int n) {
        static string strs[] ={"", "1", "11", "21", "1211", "111221"};
        if (n <= 5) return strs[n];
        else {
            string str = countAndSay(n-1);
            string ans;
            for(int i = 0; i < str.length();) {
                int j = i+1;
                while(j < str.length() && str[j] == str[i]) {
                    j++;
                }
                ans+=(char(j-i+'0'));
                ans+=(str[i]);
                i = j;
            }
            return ans;
        }
    }
};

39.Combination Sum

題目來源:https://leetcode.com/problems/combination-sum/description/

題意

大概就是可重複選取的揹包問題。

思路

採用遞歸的思想,如果lackOfNum比當前位置數字大,則選取當前數字,然後遞歸下去。如果到了某一個數字,lackOfNum==0,說明剛好滿足條件,將當前選取的數列加入答案ans中。

參考代碼

class Solution {
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        sort(candidates.begin(), candidates.end());
        vector<vector<int>> ans;
        vector<int> currentNum;
        recurse(ans, candidates, currentNum, 0, target);
        return ans;
    }

    void recurse(vector<vector<int>>& ans, vector<int>& candidates, vector<int>& currentNum, int currentPos, int lackOfNum) {
       if (0 == lackOfNum) {
           ans.push_back(currentNum);
           return;
       }
        if(currentPos < candidates.size() && lackOfNum >= candidates[currentPos]) {
            for(int i = currentPos; i != candidates.size() && candidates[i] <= lackOfNum ; i++) {
                currentNum.push_back(candidates[i]);
                recurse(ans, candidates, currentNum, i, lackOfNum-candidates[i]);
                currentNum.pop_back();
            }
        }
    }
};

41. First Missing Positive

題目來源:https://leetcode.com/problems/first-missing-positive/discuss/

題意

給出一個無序數列,要求找到第一個未出現的正數。要求時間複雜度爲O(n),空間複雜度爲O(constant)。

思路

這是參考別人的代碼,大概意思是將正數i放到第i個位置,即下標爲i-1的位置。然後遍歷這個數組,看哪個位置的元素不對,就知道哪個正數缺失。

參考代碼

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int n = nums.size(), tmp = 0;
        for(int i = 0; i < n; i++) {
            while(nums[i] > 0 && nums[i] <= n && nums[nums[i]-1] != nums[i]) {
                tmp = nums[nums[i]-1];
                nums[nums[i]-1] = nums[i];
                nums[i] = tmp;
            }
        }

        for(int i = 0; i < n; i++) {
            if(nums[i] != i+1)
                return i+1;
        }
        return n+1;
    }
};

45. Jump Game II

題目來源:https://leetcode.com/problems/jump-game-ii/description/

題意

給出一個數列nums,第i個元素就是從該點最多往前跳的步數nums[i]。問i=0最少要經過多少跳能到i=nums.size()-1。
本題應該要求的是O(n),因爲我寫遞推加記憶化搜索,O(n^2)是超時的。

思路

參考了discussion裏的答案,用的是BFS,但不是傳統的BFS,因爲不需要用到一個隊列實例。
思想是極其精妙的:將數列劃分爲各個level,第i層就是從起點經過i跳可以到達的點。代碼只保存了當前層最遠的點(最遠的都跳到,進的肯定能到),然後遍歷這層的點,尋找到下一層能到的最遠的點。然後進入下一層,繼續這個過程。直到發現終點在某個level,這就是所需的最大跳數。

簡潔!高效!美麗!

參考代碼

class Solution {
public:
    int jump(vector<int>& nums) {
        int n = nums.size();
        if(n < 2) return 0;
        int level = 0, curMax = 0, i = 0, nextMax = 0;

        while(true) {
            level++;
            for(;i <= curMax; i++) {
                nextMax = max(nextMax, nums[i]+i);
                if(nextMax >= n-1) return level;
            }
            curMax = nextMax;
        }
        return 0;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章