题一. 将有序数组转为二叉搜索树-108
1. 题目描述
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
示例 1:
输入:nums = [-10,-3,0,5,9]
输出:[0,-3,9,-10,null,5]
解释:[0,-10,5,null,-3,null,9] 也将被视为正确答案:
示例 2:
输入:nums = [1,3]
输出:[3,1]
解释:[1,3] 和 [3,1] 都是高度平衡二叉搜索树。
提示:
1 <= nums.length <= 104
-104 <= nums[i] <= 104
nums 按 严格递增 顺序排列
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2. 提交代码
思路:选取数组的某个元素作为根节点,然后构建左右子树,对左右子树也是每次选取数组的某个元素作为根节点来构建子子树,可以看出这个构建过程是递归的。因为题目要求该二叉搜索树是平衡的,所以我们每次选取有序数组的中间元素作为根节点。
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {number[]} nums
* @return {TreeNode}
*/
var sortedArrayToBST = function(nums) {
if(nums.length === 1){
return new TreeNode(nums[0]);
}
return createTree(nums, 0, nums.length-1);
};
function createTree(nums, start, end){
if(end < start){
return null;
}
let mid = Math.floor(start + (end-start)/2);
let root = new TreeNode(nums[mid]);
root.left = createTree(nums, start, mid-1);
root.right = createTree(nums, mid+1, end);
return root;
};
时间复杂度:O(n),遍历数组的每个元素;
空间复杂度:O(logn)。
题二. 组合-77
1. 题目描述
给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。
示例:
输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/combinations
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2. 提交代码
思路:这个是我根据做过的 46.全排列的题写的代码,在回溯里修改了条件,一是当path长度为k时就记录答案,保证是选择了k个数字,二是为了避免 res 中记录到 [2,3] 和 [3,2] 相同的答案,要求在选数字加入数组path时是升序的,这样就避免了 [3,2]的出现。
分析:这种写法不推荐,因为运行时间较长,时间复杂度应该是O(k*n!)。
/**
* @param {number} n
* @param {number} k
* @return {number[][]}
*/
var combine = function(n, k) {
const res = [];
const path = [];
if(k > n){
k = n;
}
backtrack(n, k, path, res);
return res;
};
function backtrack(n, k, path, res){
if(k === path.length){
res.push(path.slice());
return;
}
for(let num = 1; num <= n; num++){
if(path.includes(num)){
continue;
}
if(path.length === 0 || (path.length > 0 && num > path[path.length-1])){
path.push(num);
backtrack(n, k, path, res);
path.pop();
}
}
};
推荐写法:
/**
* @param {number} n
* @param {number} k
* @return {number[][]}
*/
var combine = function(n, k) {
const res = [];
const temp = [];
combineCore(n, k, 1, temp, res);
return res;
};
function combineCore(n, k, curr, temp, res){
//剪枝,这里说明构不成长度为k的temp
if(temp.length + (n-curr+1) < k){
return;
}
//记录合法答案
if(temp.length === k){
res.push(temp.slice());
return;
}
//选择curr
combineCore(n, k, curr+1, [...temp, curr], res);
//不选curr
combineCore(n, k, curr+1, temp, res);
};
时间复杂度:O(C(n,k)*k),枚举的时间是C(n,k),将答案复制到res里的时间是O(k)。
空间复杂度:O(n+k)=O(n),递归栈深度O(n)和开辟临时数组O(k)。