【算法設計作業】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;
}
我們用二分搜索的思想,首先求出x
和y
的中值,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;
}
};