日练三题,冰冻三尺非一日之寒。
Given n, how many structurally unique BST’s (binary search trees) that store values 1…n?
For example,
Given n = 3, there are a total of 5 unique BST’s.
1 3 3 2 1
\ / / / \ \
3 2 1 1 3 2
/ / \ \
2 1 2 3
题意:n个节点的二分查找树有多少种组成可能。
思路:
这道题是考察卡特兰数的计算。
n个节点构成的BST,共有多少种情形?
可以这样考虑,根肯定会占用一个结点,那么剩余的n-1个结点可以有如下的分配方式,T(0, n-1),T(1, n-2),…T(n-1, 0),设T(i, j)表示根的左子树含i个结点,右子树含j个结点。
设问题的解为f(n),那么f(n) = f(0)*f(n-1) + f(1)*f(n-2) + …….+ f(n-2)*f(1) + f(n-1)*f(0)。假设f(0) = 1,那么f(1) = 1, f(2) = 2, f(3) = 5。n个节点的组合数就是f(n)。
用DP来解决
代码:
class Solution {
public:
int numTrees(int n) {
vector<long> f(n+1,0);
f[0] = 1;
f[1] = 1;
for(int i=2;i<=n;i++)
{
long tmp=0;
for(int j=0;j<i;j++)
{
tmp+=f[j]*f[i-1-j];
}
f[i] = tmp;
}
return f[n];
}
};
结果:0ms
2、根据卡特兰数的计算方法,(2n!)/[(n+1)!*(n!)] =(2n!)/[2(n!)*n+1]
class Solution {
public:
int numTrees(int n) {
return calcFactorial(2*n)/(calcFactorial(n+1)*calcFactorial(n));
}
int calcFactorial(int m)
{
int res = 1;
for(int i=2;i<=m;i++)
res*=i;
return res;
}
};
结果:Runtime Error
测试样例中n=19的时候无法计算,换成python试一下
class Solution(object):
def numTrees(self, n):
""" :type n: int :rtype: int """
from math import factorial
return factorial(2*n)/(factorial(n)*factorial(n+1))
结果:40ms
Given an array where elements are sorted in ascending order, convert it to a height balanced BST.
题意:将一个排列好的数组变成一棵 height balanced BST(平衡二分查找树)。
思路:
如何生成一棵平衡的BST?首先可以肯定的一点是完全二叉树一定是平衡的BST。
不妨先看一个完全二叉树的栗子:
这是一棵满的平衡BST,我们中徐序遍历一次这棵树,看看会出现什么结果。
[1,2,4,5,6,8,9]
根节点是第3个元素(从0开始计数),3=(0+6)/2。左子树的根节点是第1个元素,1=(0+2)/2,右子树的根节点是第5个元素,5=(4+6)/2。
是不是很熟悉,没错,就是在做二分查找,基于这个思路不难写出下面代码。
/** * 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* sortedArrayToBST(vector<int>& nums) {
if(nums.size()==0) return NULL;
TreeNode * root = findRoot(nums,0,nums.size()-1);
return root;
}
TreeNode * findRoot(vector<int>&nums ,int low, int high)
{
if(low>high) return NULL;
int mid = low+((high-low)>>1);
TreeNode *root = new TreeNode(nums[mid]);
root->left = findRoot(nums,low,mid-1);
root->right = findRoot(nums,mid+1,high);
return root;
}
};
结果:16ms
Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
You may assume no duplicates in the array.
Here are few examples.
[1,3,5,6], 5 → 2
[1,3,5,6], 2 → 1
[1,3,5,6], 7 → 4
[1,3,5,6], 0 → 0
题意:排序数组元素查找问题,如果找到了返回index,找不到就返回其应该插入的位置。
思路:
1、如果在列表中,直接用python的index方法返回index,如果不在,去找第一个比target大的index。
class Solution(object):
def searchInsert(self, nums, target):
""" :type nums: List[int] :type target: int :rtype: int """
if target in nums:
return nums.index(target)
else:
length = len(nums)
for i in nums:
if i>target:
return nums.index(i)
return len(nums)
结果:44ms
2、其实问题等价于从一个排序好的数组中去查找第一个大于等于目标数的元素的下标,那么这么想就很简单了,直接用二分查找的方法。
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int low=0,high=nums.size()-1;
while(low<=high)
{
int mid = low+((high-low)>>1);
if(nums[mid]>=target) high=mid-1;
else low = mid+1;
}
return low;
}
};
结果:8ms
Find all possible combinations of k numbers that add up to a number n, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers.
Example 1:
Input: k = 3, n = 7
Output:
[[1,2,4]]
Example 2:
Input: k = 3, n = 9
Output:
[[1,2,6], [1,3,5], [2,3,4]]
题意:从1-9中挑选k个数,使得其累加和等于整数n,且每个数字只能够用一次。
思路:
Example 2:
Input: k = 3, n = 9
Output:
[[1,2,6], [1,3,5], [2,3,4]]
回溯思想,首先从1开始,尝试1\2\3,发现不行之后弹出3,尝试1\2\4.依次类推。什么时候回溯呢?就是当已经凑够了k个数字,它们的和确不等于n,这个时候显然无法得到我们希望的结果,进行回溯再试下一个末位数。直到最初的第一层递归调用,也就是第一位数字也循环完毕了,说明无更多情况,程序结束。
class Solution {
public:
vector<vector<int>> combinationSum3(int k, int n) {
vector<vector<int>> result;
vector<int> tmp;
combination(result,tmp,1,k,n);
return result;
}
void combination(vector<vector<int>> &result,vector<int>tmp,int start,int k,int n)
{
if(k==0&&n==0) { result.push_back(tmp); return; }
for(int i=start;i<=10-k&&i<=n;i++)
{
tmp.push_back(i);
combination(result,tmp,i+1,k-1,n-i);
tmp.pop_back();
}
}
};
结果:4ms
2、另外一种类似的写法,参照https://discuss.leetcode.com/topic/14641/my-c-solution-backtracking/6
class Solution {
public:
vector<vector<int>> combinationSum3(int k, int n) {
vector<vector<int>> result;
vector<int> tmp;
combination(result,tmp,k,n);
return result;
}
void combination(vector<vector<int>> &result,vector<int>tmp,int k,int n)
{
if(tmp.size()==k&&n==0) { result.push_back(tmp); return; }
if(tmp.size()<k)
{
for(int i=tmp.empty()? 1:tmp.back()+1;i<10;i++)
{
tmp.push_back(i);
combination(result,tmp,k,n-i);
tmp.pop_back();
}
}
}
};
结果:4ms