【算法设计作业】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;
}
};