void traverse(int[] arr){ for(int i=0;i<arr.length;i++){ //迭代访问arr[i] } }
class ListNode{ int val; ListNode next; } void traverse(ListNode head){ for(ListNode p=head;p!=null;p=p.next){ //迭代遍历p.val } } void traverse(ListNode head){ //先序遍历head.val traverse(head.next); //后序遍历head.val }
class TreeNode{ int val; TreeNode left,right; } void traverse(TreeNode root){ //前序遍历 traverse(root.left); //中序遍历 traverse(root.right); //后续遍历 }
class TreeNode{ int val; TreeNode[] children; } void traverse(TreeNode root){ for(TreeNode child:root.children){ traverse(child); } }
void traverse(TreeNode root){ //前序遍历 traverse(root.left); //中序遍历 traverse(root.right); //后续遍历
void backtrack(int[] nums,LinkedList<Integer> track){ if(track.size()==nums.length){ res.add(new LinkedList(track)); return ; } for(int i=0;i<nums.length;i++){ if(track.contains(nums[i])){ continue; } track.add(nums[i]); //进入下一层决策树 backtrack(nums,track); track.removeLast(); } //提取N叉树遍历框架 void backtrack(int[] nums,LinkedList<Integer> track){ for(int i=0;i<nums.length;i++){ backtrack(nums,track); } } }
框架
初始化base dp[0][0][……]=base case 状态转移 for(状态1 in 状态1的所有取值) for(状态2 in 状态2的所有取值) for…… dp[状态1][状态2][……]=求最值(选择1,选择2……)
int fib(int N){ if(N==0){ return 0; } if(N==1||N==2){ return 1; } return fib(N-1)+fib(N-2); }
int fib(int N){ if(N==0){ return 0; } vector<int> memo(N+1,0); return helper(memo,N); } int helper(vector<int>& memo,int n){ if(n==1||n==2){ return 1; } if(memo[n]!=0){ return memo[n]; } memo[n]=helper(memo,n-1)+helper(memo,n-2); return memo[n]; }
int fib(int N){ if(N==0) return 0; if(N==1||N==2) return 1; vector<int> dp(N+1,0); dp[1]=dp[2]=1; for(int i=3;i<=N;i++) dp[i]=dp[i-1]+dp[i-2]; return dp[N]; }
int fib(int n){ if(n==0){ return 0; } if(n==1||n==2){ return 1; } prev=1,curr=1; for(int i=3;i<=n;i++){ int sum=prev+curr; prev=curr; curr=sum; } return curr; }
int coinChange(int[] coins,int amount){ int dp(int n){ int res=0; for(int coin=0;coin<=coins;coin++){ res=min(res,1+dp(n-coin)) } return res; } return dp(amount); }
int coinChange(int[] coins,int amount){ int dp(int n){ if(n==0) return 0; else if(n<0) return -1; res=INT_MAX for(int coin=0;coin<=coins;coin++){ int subproblem=-1; subproblem=dp(n-coin); if(subproblem==-1) continue; int res; res=min(res,1+subproblem); } if(res>0){ return res; } else { return 0; } } return dp(amount); }
int coinChange(vector<int>& coins,int amount){ //数组大小为amount+1,初始值为amount+1 vector<int> dp(amount+1,amount+1); //base case dp[0]=0; //外层for循环遍历所有状态的所有取值 for(int i=0;i<dp.size();i++){ //内层for循环求所有选择的最小值 for(int coin:coins){ //子问题无解跳过 if(i-coin<0){ continue; } dp[i]=min(dp[i],1+dp[i-coins]); } } return (dp[amount]==amount+1)?-1:dp[amount]; }
result=[]; int backtrack(路径,选择列表){ if(满足结束条件){ result.add(路径) return } for(选择 in 选择列表){ 做选择 backtrack(路径,选择列表) 撤销选择 } }
void traverse(TreeNode root){ for(TreeNode child:root.children){ //前序遍历的操作 traverse(child); //后序遍历需要的操作 } }
for 选择 in 选择列表: #做选择 将该选择从选择列表中移除 路径.add(选择) backtrack(路径,选择列表) #撤销选择 路径.remove(选择) 将该选择恢复到选择列表
List<List<Integer>> res=new LinkedList<>(); List<List<Integer>> premute(int[] nums){ //记录路径 LinkedList<Integer> track=new LinkedList<>(); backtrack(nums,track); return res; } /**路径:记录在track中 选择列表:在nums中不存在于track的那些元素 结束条件:nums中的元素全都在track中出现**/ void backtrack(int[] nums,LinkedList<Integer> track){ //触发结束条件 if(track.size()==nums.length){ res.add(new LinkedList(track)); return; } for(int i=0;i<nums.length;i++){ //排除不合法的选择 if(track.contains(nums[i])) continue; //做选择 track.add(nums[i]); //进入下一层决策树 backtrack(nums,track); //取消选择 track.removeLast(); } }
vector<vector<string>> res; /*输入棋盘边长n,返回所有合法的放置方法 */ vector<vector<string>> solveNQueens(int n){ //'.'表示空,'Q'表示皇后,初始化空棋盘 vector<string> board(n,string(n,'''''.''''')); backtrack(board,0); return res; } /**路径:board中小于row的那些行都已经成功放置了皇后 选择列表:第row行的所有列都是放置皇后的选择 结束条件:row超过board的最后一行,说明棋盘放满了**/ void backtrack(vector<string>& board, int row){ if(row==board.size()){ res.push_back(board); return; } int n = board[row].size(); for(int col=0;col<n;col++){ //排除不满足选择 if(!isValid(board,row,col)) continue; //做选择 board[row][col]='Q'; //进入下一个决策 backtrack(board,row+1); //撤销选择 board[row][col]='.'; } }
/*是否可以在board[row][col]放置皇后*/ bool isValid(vector<string>& board,int row,int col){ int n=board.size(); //检查列中是否有皇后相互冲突 for(int i=0;i<row;i++){ if(board[i][col]=='Q') return false; } //检查右上方是否有皇后互相冲突 for(int i=row-1;j=col+1;i>=0&&j<n;i--,j++){ if(board[i][j]=='Q') return false; } //检查左上方是否有皇后冲突 for(int i=row-1,j=col-1;i>=0&&j>=0;i--,j--){ if(board[i][j]=='Q') return false; } return true; }
//函数找到一个答案后就返回true bool backtrack(vector<string>& board,int row){ if(row==board.size()){ res.push_back(board); return true; } int n=board[row].size(); for(int cpl=0;col<n;col++){ if(!isValid(board,row,col)) continue; //做选择 board[row][col]='Q'; //进入下一行决策 if(backtrack(board,row+1)) return true; //撤销选择 board[row][col]='.'; } return false; }
1.3.3总结
int backtrack(……){ for(选择 in 选择列表){ 做选择 backtrack(……); 撤销选择 } }