日练三题,冰冻三尺非一日之寒。
Suppose a sorted array is rotated at some pivot unknown to you beforehand.
(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).
Find the minimum element.
You may assume no duplicate exists in the array.
题意:一个已经经过移位的数组,找出其中最小的元素,假设没有重复元素的存在。
思路:
1、一个时间复杂度为O(N)的方法,遍历数组的元素,如果如果后一个元素比前一个小,那么那个就是我们要找的。
class Solution {
public:
int findMin(vector<int>& nums) {
for(int i=0;i<nums.size()-1;i++)
{
if(nums[i]>nums[i+1]) return nums[i+1];
}
return nums[0];
}
};
结果:4ms
2、直接用二分查找的思想,mid=left+(right-left)/2;如果nums[mid]>nums[right],就说明待查找元素在mid位置元素的右边,left=mid+1,如果nums[mid]
class Solution {
public:
int findMin(vector<int>& nums) {
int left = 0,right=nums.size()-1;
while(left<right)
{
if(nums[left]<nums[right]) return nums[left];
int mid = left+(right-left)/2;
if(nums[mid]>nums[right]) left = mid+1;
else right = mid;
}
return nums[left];
}
};
结果:4ms
Given two integers n and k, return all possible combinations of k numbers out of 1 … n.
For example,
If n = 4 and k = 2, a solution is:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
题意:给定n和k,写出所有n个数中选k个数的组合。
思路:
1、直接回溯就可以搞定
class Solution {
public:
vector<vector<int>> combine(int n, int k) {
vector<vector<int>> res;
vector<int> tmp;
combineSub(res,tmp,n,k);
return res;
}
void combineSub(vector<vector<int>> &res,vector<int>tmp,int n,int k )
{
if(k==0)
{
res.push_back(tmp);
return;
}
if(k>0)
{
for(int i=tmp.empty()?1:tmp.back()+1;i<=n;i++)
{
tmp.push_back(i);
combineSub(res,tmp,n,k-1);
tmp.pop_back();
}
}
}
};
结果:580ms
居然这么慢,应该是有什么地方没写对
稍微改进下
class Solution {
public:
vector<vector<int>> combine(int n, int k) {
vector<vector<int>> res;
vector<int> tmp(k,0);
combineSub(res,tmp,1,n,k);
return res;
}
void combineSub(vector<vector<int>> &res,vector<int>tmp,int start,int n,int k )
{
if(k==0)
{
res.push_back(tmp);
return;
}
for(int i=start;i<=n-k+1;i++)
{
tmp[tmp.size()-k]=i;
combineSub(res,tmp,i+1,n,k-1);
tmp[tmp.size()-1] = 0;
}
}
};
结果:92ms
2、再做一点改进
class Solution {
public:
vector<vector<int> > combine(int n, int k) {
// dfs method
if(k == 0 || n == 0 || n<k)
return result;
v.resize(k);
combinecore(1, n, k);
return result;
}
void combinecore(int start, int n, int k) {
int i = start;
while(i<=(n-k+1)) {
v[v.size()-k] = i;
i++;
if(k>1)
combinecore(i, n, k-1);
else
result.push_back(v);
}
}
private:
vector<int> v;
vector<vector<int> > result;
};
结果:84ms
Given a string of numbers and operators, return all possible results from computing all the different possible ways to group numbers and operators. The valid operators are +, - and *.
Example 1
Input: “2-1-1”.
((2-1)-1) = 0
(2-(1-1)) = 2
Output: [0, 2]
Example 2
Input: “2*3-4*5”
(2*(3-(4*5))) = -34
((2*3)-(4*5)) = -14
((2*(3-4))*5) = -10
(2*((3-4)*5)) = -10
(((2*3)-4)*5) = 10
Output: [-34, -14, -10, -10, 10]
题意:寻找不同的加括号方式,将可能得到的计算值返回。
思路:
1、首先思考一个问题,先不考虑如何计算具体加括号之后的数值,先想下有多少种加括号的方法?经过试验:有1个运算符只有一个划分方式,有2个运算符有5种划分方式,有3个运算符有14种划分方式。是不是对这个式子很熟悉,没错,加括号的方法数就是一个卡特兰数,当算式中有n个运算符的时候,一共就有f(n)=(2n!)/(n!)(n+1)!种的加括号方法,那么如何做才能做到不重复不遗漏的将每种情况都考虑进来呢?
首先,问题整体来看有些复杂,这个时候可以尝试去找下问题的子问题,从一个简单栗子来看:
2*5-3,这个式子只有2个运算符,我想一个小学毕业生应该都能知道划分方式有((2*5)-3)=7和(2*(5-3))=4这两种,两个运算符是很好看出来的,我们首先考虑第一个号,我们将号左边的结果记为res1,*号右边的结果记为res2,那么我们只需要先后计算出res1和res2,然后最后再两者相乘就是最终结果,而计算res1和res2中结果的时候,也是一样的思想,对res1中的每个算式遍历一次,对每次选中的运算符又分成两个子问题,这样递归的执行下去直到平凡情况也就是res1和res2都是一个数值,这个时候直接对两个数进行四则运算就可以了。
基于以上思路写出如下代码:
class Solution {
public:
vector<int> diffWaysToCompute(string input) {
vector<int> res;
for(int i=0;i<input.length();i++)
{
if(input[i]=='+'||input[i]=='-'||input[i]=='*')
{
string inputLeft = input.substr(0,i);
string inputRight = input.substr(i+1,input.length()-i-1);
vector<int> resLeft = diffWaysToCompute(inputLeft);
vector<int> resRight = diffWaysToCompute(inputRight);
for(auto res1:resLeft)
for(auto res2:resRight)
{
switch (input[i]) {
case '+':
res.push_back(res1+res2);
break;
case '-':
res.push_back(res1-res2);
break;
default:
res.push_back(res1*res2);
}
}
}
}
if (res.empty())
{
res.push_back(stoi(input));
}
return res;
}
};
结果:8ms
2、详见https://discuss.leetcode.com/topic/19906/c-4ms-recursive-dp-solution-with-brief-explanation
DP的思路,开创额外的空间用来保存子式的中间计算的结果,栗如:3*3*3,在以第一个分割的时候,会保存dp[“3”]=3,dp[“3*3”]=9,然后在以第二个分割的时候,左边的3*3和右边的3都在dp中有所保存,直接调用无需再去递归求。
class Solution {
public:
vector<int> diffWaysToCompute(string input) {
unordered_map<string, vector<int>> dp;
return computeWithDP(input, dp);
}
vector<int> computeWithDP(string input, unordered_map<string, vector<int>> &dp)
{
vector<int> res;
for(int i=0;i<input.length();i++)
{
if(input[i]=='+'||input[i]=='-'||input[i]=='*')
{
vector<int> resultLeft,resultRight;
string inputLeft = input.substr(0,i);
if(dp.find(inputLeft)!=dp.end()) resultLeft = dp[inputLeft];
else resultLeft = computeWithDP(inputLeft,dp);
string inputRight = input.substr(i+1,input.length()-i-1);
if(dp.find(inputRight)!=dp.end()) resultRight = dp[inputRight];
else resultRight = computeWithDP(inputRight,dp);
for(auto res1:resultLeft)
for(auto res2:resultRight)
{
switch (input[i]) {
case '+':
res.push_back(res1+res2);
break;
case '-':
res.push_back(res1-res2);
break;
default:
res.push_back(res1*res2);
}
}
}
}
if (res.empty())
{
res.push_back(stoi(input));
}
dp[input] = res;
return dp[input];
}
};
结果:4ms
Given a collection of distinct numbers, return all possible permutations.
For example,
[1,2,3] have the following permutations:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
题意:写出一个列表中元素所有排列可能性
1、python有直接现成的库可以调用
class Solution(object):
def permute(self, nums):
""" :type nums: List[int] :rtype: List[List[int]] """
import itertools
permute = list(itertools.permutations(nums))
permute = [list(i) for i in permute]
return permute
结果:86ms
2、但是做题不能总是import,so考虑用下迭代器
class Solution(object):
def permute(self, nums):
""" :type nums: List[int] :rtype: List[List[int]] """
def gen(nums):
if not nums:
yield []
for i, n in enumerate(nums):
for p in gen(nums[:i] + nums[i+1:]):
yield [n] + p
return list(gen(nums))
结果:92ms
3、可以用DFS来做
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int>> res;
dfs(nums,0,res);
return res;
}
void dfs(vector<int>& nums,int start,vector<vector<int>>& res)
{
if(start>=nums.size())
{
res.push_back(nums);
return ;
}
for(int i=start;i<nums.size();i++)
{
swap(nums[i],nums[start]);
dfs(nums,start+1,res);
swap(nums[i],nums[start]);
}
}
};
结果:12ms