給定一個二叉樹,根節點爲第1層,深度爲 1。在其第 d 層追加一行值爲 v 的節點。node
添加規則:給定一個深度值 d (正整數),針對深度爲 d-1 層的每一非空節點 N,爲 N 建立兩個值爲 v 的左子樹和右子樹。 數組
將 N 原先的左子樹,鏈接爲新節點 v 的左子樹;app
將 N 原先的右子樹,鏈接爲新節點 v 的右子樹。 ui
若是 d 的值爲 1,深度 d - 1 不存在,則建立一個新的根節點 v,原先的整棵樹將做爲 v 的左子樹。this
Input: A binary tree as following: 4 / \ 2 6 / \ / 3 1 5 v = 1 d = 2 Output: 4 / \ 1 1 / \ 2 6 / \ / 3 1 5 來源:力扣(LeetCode) 連接:https://leetcode-cn.com/problems/add-one-row-to-tree
/** * @param {number} cd:current depth,遞歸當前深度 * @param {number} td:target depth, 目標深度 */ var traversal = function (node, v, cd, td) { // 遞歸到目標深度,建立新節點並返回 if (cd === td) { // return 新節點 } // 向左子樹遞歸 if (node.left) { node.left = traversal (node.left, v, cd + 1, td); } // 向右子樹遞歸 if (node.right) { node.right = traversal (node.right, v, cd + 1, td); } // 返回舊節點 return node; }; /** * Definition for a binary tree node. * function TreeNode(val) { * this.val = val; * this.left = this.right = null; * } */ /** * @param {TreeNode} root * @param {number} v * @param {number} d * @return {TreeNode} */ var addOneRow = function (root, v, td) { // 從根節點開始遞歸 traversal (root, v, 1, td); return root; };
若是目標節點原來是左子樹,那麼重置後目標節點是val節點的左子樹spa
若是目標節點原來是右子樹,那麼重置後目標節點是val節點的右子樹debug
咱們再分析題意,題目裏說:「若是 d 的值爲 1,深度 d - 1 不存在,則建立一個新的根節點 v,原先的整棵樹將做爲 v 的左子樹。」3d
/** * @param {v} val,插入節點攜帶的值 * @param {cd} current depth,遞歸當前深度 * @param {td} target depth, 目標深度 * @param {isLeft} 判斷原目標深度的節點是在左子樹仍是右子樹 */ var traversal = function (node, v, cd, td, isLeft) { debugger; if (cd === td) { const newNode = new TreeNode (v); // 若是原來是左子樹,重置後目標節點仍是在左子樹上,不然相反 if (isLeft) { newNode.left = node; } else { newNode.right = node; } return newNode; } // 處理上述的第1和第2種狀況 if (node.left || (node.left === null && cd + 1 === td)) { node.left = traversal (node.left, v, cd + 1, td, true); } if (node.right || (node.right === null && cd + 1 === td)) { node.right = traversal (node.right, v, cd + 1, td, false); } return node; }; /** * Definition for a binary tree node. * function TreeNode(val) { * this.val = val; * this.left = this.right = null; * } */ /** * @param {TreeNode} root * @param {number} v * @param {number} d * @return {TreeNode} */ var addOneRow = function (root, v, td) { // 處理目標深度爲1的狀況,也就是上述的第3種狀況 if (td === 1) { const n = new TreeNode (v); n.left = root; return n; } traversal (root, v, 1, td); return root; };
給定一個非空字符串 s 和一個包含非空單詞列表的字典 wordDict,斷定 s 是否能夠被空格拆分爲一個或多個在字典中出現的單詞。 code
說明:orm
1.拆分時能夠重複使用字典中的單詞。
2.你能夠假設字典中沒有重複的單詞。
example1 輸入: s = "applepenapple", wordDict = ["apple", "pen"] 輸出: true 解釋: 返回 true 由於 "applepenapple" 能夠被拆分紅 "apple pen apple"。 注意: 你能夠重複使用字典中的單詞。 example2 輸入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"] 輸出: false 來源:力扣(LeetCode) 連接:https://leetcode-cn.com/problems/word-break
動態規劃
wordDict = ['ab','cd','ef']
s ='abcdef'
而且假設目前咱們已經得出了N=1到N=5的狀況,而如今須要計算N=6的狀況
A序列 + B序列 1.abcdef + "" 2.abcde + f 3.abcd + ef 4.abc + def 5.ab + cdef 6.a + bcdef 注意:當A可拆且B可拆時,則A+B也是可拆分的
從中咱們不難發現兩點
當A可拆且B可拆時,則A+B也是可拆分的
這6種狀況只要有一種組合序列是可拆分的,abcdef就必定是可拆的,也就得出dp[6] = true了
var initDp = function (len) { let dp = new Array (len + 1).fill (false); return dp; }; /** * @param {string} s * @param {string[]} wordDict * @return {boolean} */ var wordBreak = function (s, wordDict) { // 處理空字符串 if (s === '' && wordDict.indexOf ('') === -1) { return false; } const len = s.length; // 默認初始值所有爲false const dp = initDp (len); const a = s.charAt (0); // 初始化動態規劃的初始值 dp[0] = wordDict.indexOf (a) === -1 ? false : true; dp[1] = wordDict.indexOf (a) === -1 ? false : true; // i:end // j:start for (let i = 1; i < len; i++) { for (let j = 0; j <= i; j++) { // 序列[0,i] = 序列[0,j] + 序列[j,i] // preCanBreak表示序列[0,j]是不是可拆分的 const preCanBreak = dp[j]; // 截取序列[j,i] const str = s.slice (j, i + 1); // curCanBreak表示序列[j,i]是不是可拆分的 const curCanBreak = wordDict.indexOf (str) !== -1; // 狀況1: 序列[0,j]和序列[j,i]均可拆分,那麼序列[0,i]確定也是可拆分的 const flag1 = preCanBreak && curCanBreak; // 狀況2: 序列[0,i]自己就存在於字典中,因此是可拆分的 const flag2 = curCanBreak && j === 0; if (flag1 || flag2) { // 設置bool值,本輪計算結束 dp[i + 1] = true; break; } } } // 返回最後結果 return dp[len]; };
給定一個沒有重複數字的序列,返回其全部可能的全排列。
輸入: [1,2,3] 輸出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] 來源:力扣(LeetCode) 連接:https://leetcode-cn.com/problems/permutations
基本思想
回溯法
深度優先搜索搞一波,index在遞歸中向前推動
當index等於數組長度的時候,結束遞歸,收集到results中(數組記得要深拷貝哦)
兩次數字交換的運用,計算出兩種狀況
想不通不要緊,套路一波就完事了
var swap = function (nums, i, j) { const temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; }; var recursion = function (nums, results, index) { // 剪枝 if (index >= nums.length) { results.push (nums.concat ()); return; } // 初始化i爲index for (let i = index; i < nums.length; i++) { // index 和 i交換?? // 統計交換和沒交換的兩種狀況 swap (nums, index, i); recursion (nums, results, index + 1); swap (nums, index, i); } }; /** * @param {number[]} nums * @return {number[][]} */ var permute = function (nums) { const results = []; recursion (nums, results, 0); return results; };