1137. 第 N 个泰波那契数
【代码一】超时
class Solution {
public int tribonacci(int n) {
if(n == 0){
return 0;
}
if(n == 1 || n == 2){
return 1;
}
return tribonacci(n-1) + tribonacci(n-2) + tribonacci(n-3);
}
}
【代码二】通过—动态规划
class Solution {
public int tribonacci(int n) {
if(n == 0){
return 0;
}
if(n == 1 || n == 2){
return 1;
}
int[] dp = new int[n+1];
dp[0] = 0;
dp[1] = dp[2] = 1;
for(int i = 3; i <= n; i++){
dp[i] = dp[i-1] + dp[i-2] + dp[i-3];
}
return dp[n];
}
}
【代码三】通过—记忆搜索
class Solution {
private int[] dp; // 记忆数组
public int tribonacci(int n) {
if(n == 0){
return 0;
}
if(n == 1 || n == 2){
return 1;
}
dp = new int[n+1];
dp[0] = 0;
dp[1] = dp[2] = 1;
for(int i = 3; i <= n; i++){
dp[i] = -1;
}
return solve(n);
}
private int solve(int n){
if(dp[n] == -1){
dp[n] = solve(n-1) + solve(n-2) + solve(n-3);
}
return dp[n];
}
}
【代码四】通过—三个变量直接递推
class Solution {
public int tribonacci(int n) {
if(n == 0){
return 0;
}
if(n == 1 || n == 2){
return 1;
}
// 直接用三个变量递推,类似于动态规划,但不记录中间结果
int a = 0;
int b = 1;
int c = 1;
int tmp;
for(int i = 3; i <= n; i++){
tmp = a + b + c;
a = b;
b = c;
c = tmp;
}
return c;
}
}
【代码五】通过—直接打表(利用题目数据范围)
class Solution {
private int[] table = {
0, 1, 1, 2, 4, 7, 13, 24, 44, 81, 149, 274, 504, 927, 1705, 3136, 5768, 10609, 19513, 35890, 66012, 121415,223317, 410744, 755476, 1389537, 2555757, 4700770, 8646064, 15902591, 29249425, 53798080, 98950096, 181997601,334745777, 615693474, 1132436852, 2082876103};
public int tribonacci(int n) {
return table[n];
}
}
938. 二叉搜索树的范围和
【代码一】通过—二叉搜索树遍历
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int rangeSumBST(TreeNode root, int L, int R) {
if(root == null){
return 0;
}
if(root.val < L){
return rangeSumBST(root.right, L, R);
}
if(root.val > R){
return rangeSumBST(root.left, L, R);
}
return rangeSumBST(root.left, L, R) + rangeSumBST(root.right, L, R) + root.val;
}
}
【代码二】通过—普通二叉树遍历
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int rangeSumBST(TreeNode root, int L, int R) {
if(root == null){
return 0;
}
if(root.val < L || root.val > R){
return rangeSumBST(root.right, L, R) + rangeSumBST(root.left, L, R);
}
return rangeSumBST(root.left, L, R) + rangeSumBST(root.right, L, R) + root.val;
}
}
894. 所有可能的满二叉树
【代码一】通过—暴力递归
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<TreeNode> allPossibleFBT(int N) {
/**
确定是什么问题重要。。整棵树是”满二叉树“,以每个节点为根的子树也是”满二叉树“,
这就是递归了。。
节点总数是N,首先N必定是奇数,递归结束条件易定,N为偶数或N=1。递归拆解子问题
FBT(N) = {x >= 1 && x < N, 递归左子树FBT(x),递归右子树FBT(N-1-x),1->根
*/
List<TreeNode> ans = new ArrayList<>();
if(N == 1){
ans.add(new TreeNode(0));
return ans;
}
if(N % 2 == 0){
return ans;
}
for(int x = 1; x < N; x += 2){
List<TreeNode> leftT = allPossibleFBT(x);
List<TreeNode> rightT = allPossibleFBT(N-1-x);
for(TreeNode l : leftT){
for(TreeNode r : rightT){
TreeNode root = new TreeNode(0);
root.left = l;
root.right = r;
ans.add(root);
}
}
}
return ans;
}
}
【代码二】通过—记忆化搜索
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private Map<Integer, List<TreeNode> > map = new HashMap<>();
public List<TreeNode> allPossibleFBT(int N) {
/**
确定是什么问题重要。。整棵树是”满二叉树“,以每个节点为根的子树也是”满二叉树“,
这就是递归了。。
节点总数是N,首先N必定是奇数,递归结束条件易定,N为偶数或N=1。递归拆解子问题
FBT(N) = {x >= 1 && x < N, 递归左子树FBT(x),递归右子树FBT(N-1-x),1->根
*/
if(map.containsKey(N)){
return map.get(N);
}
List<TreeNode> ans = new ArrayList<>();
if(N == 1){
ans.add(new TreeNode(0));
return ans;
}
if(N % 2 == 0){
return ans;
}
for(int x = 1; x < N; x += 2){
List<TreeNode> leftT = allPossibleFBT(x);
List<TreeNode> rightT = allPossibleFBT(N-1-x);
for(TreeNode l : leftT){
for(TreeNode r : rightT){
TreeNode root = new TreeNode(0);
root.left = l;
root.right = r;
ans.add(root);
}
}
}
map.put(N, ans);
return ans;
}
}
783. 二叉搜索树结点最小距离
【代码一】通过—欠妥暴力思路
遍历出来,搞成一个数组,排序,遍历一遍比较搞定。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private List<Integer> list = new ArrayList<>();
public int minDiffInBST(TreeNode root) {
dfs(root);
Collections.sort(list, new Comparator<Integer>(){
public int compare(Integer x, Integer y){
return x - y;
}
});
int min = Integer.MAX_VALUE;
for(int i = 1; i < list.size(); i++){
if(list.get(i) - list.get(i-1) < min){
min = list.get(i) - list.get(i-1);
}
}
return min;
}
private void dfs(TreeNode root){
if(root != null){
list.add(root.val);
dfs(root.left);
dfs(root.right);
}
}
}
【代码二】通过—利用二叉搜索树性质,边遍历边比较
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private TreeNode pre = null;
private int min = Integer.MAX_VALUE;
public int minDiffInBST(TreeNode root) {
dfs(root);
return min;
}
private void dfs(TreeNode root){
if(root != null){
dfs(root.left);
if(pre != null){
min = min > root.val - pre.val ? root.val - pre.val : min;
}
pre = root;
dfs(root.right);
}
}
}
779. 第K个语法符号
【代码一】超时—暴力递归
class Solution {
public int kthGrammar(int N, int K) {
String s = f(N);
return s.charAt(K-1) - '0';
}
private String f(int N){
if(N == 1){
return "0";
}
String s = f(N-1);
String obj = "";
for(int i = 0; i < s.length(); i++){
obj += s.charAt(i) == '0' ? "01" : "10";
}
return obj;
}
}
【代码二】通过—找规律
class Solution {
public int kthGrammar(int N, int K) {
// 与其说递归,不如说是找规律。。
// 第N行前一半和第N-1行完全一样。
// 第N行后一半和第N-1行完全相反。
if(N == 1){
return 0;
}
int len = (1 << (N-2)); // 第N行长度
if(K <= len){
return kthGrammar(N-1, K);
}
return 1 - kthGrammar(N-1, K-len); // 0转成1,1转成0
}
}
【代码三】通过—借助二叉树
class Solution {
public int kthGrammar(int N, int K) {
// 看成是二叉树
// 0的左孩子是0,右孩子是1。1与之相反。K的奇偶可定左孩子还是右孩子
// 关键问题就是找父亲是1还是0,递归往上走。
// 树的每层都是从1开始数
// K为偶数时,kthGrammar(N, K)的父亲是kthGrammar(N, K/2)
// K为奇数时,kthGrammar(N, K)的父亲是kthGrammar(N, (K+1)/2)
if(N == 1){
return 0;
}
if(K % 2 == 0){
return 1 - kthGrammar(N-1, K/2);
}else{
return kthGrammar(N-1, (K+1)/2);
}
}
}
698. 划分为k个相等的子集
【代码一】通过—暴力回溯
class Solution {
public boolean canPartitionKSubsets(int[] nums, int k) {
// 回溯法。
// 先对数组求和得sum及最大值max,
// 1.若sum%k != 0 || max > sum/k(此max无法放入任一个桶),返回false
// 2.搞成K个桶,每个桶初始值都是0,尝试每个数依次放入不同桶中,如果所有桶
// 都能达到sum/k,就返回true。尝试所有情况都不行,那就返回false
int sum = 0;
int max = 0; // 因为nums[i]>0
for(int i = 0; i < nums.length; i++){
sum += nums[i];
max = max < nums[i] ? nums[i] : max;
}
if(sum % k != 0 || max > sum/k){
return false;
}
int[] bucket = new int[k];
Arrays.fill(bucket, 0);
return backtrack(nums, k, bucket, sum/k, 0);
}
// cur ---> 尝试放当前值nums[cur]放入某个桶
private boolean backtrack(int[] nums, int K, int[] bucket, int avg, int cur){
if(cur >= nums.length){ // 已经尝试放完了所有的值到K个桶中
return true;
}
for(int i = 0; i < K; i++){
// 某值nums[cur]满足啥标准才放入桶bucket[i]中,这是关键
if(bucket[i] + nums[cur] <= avg){
bucket[i] += nums[cur]; // TODO,若需记录实际每个桶中有哪些值,可以在这里记录
// dfs,直至搜出一条路,或不满足回退
if(backtrack(nums, K, bucket, avg, cur+1)){
return true;
}else{
bucket[i] -= nums[cur];
}
}
}
// 已经尝试所有情况,都没有返回true,说明没有解
return false;
}
}
687. 最长同值路径
【代码一】通过—二叉树递归遍历
参考资料链接
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private int ans;
public int longestUnivaluePath(TreeNode root) {
ans = 0;
len(root);
return ans;
}
// 记录以某个节点作为根,包含根的左右单侧最长路径
private int len(TreeNode root){
if(root == null){
return 0;
}
int left = len(root.left);
int right = len(root.right);
int leftL = 0, rightL = 0;
if(root.left != null && root.val == root.left.val){
leftL = left + 1;
}
if(root.right != null && root.val == root.right.val){
rightL = right + 1;
}
ans = Math.max(ans, leftL + rightL);
return Math.max(leftL, rightL);
}
}