1.简单递归算法设计
1.1 斐波那契数
斐波那契数 (通常用 F(n)
表示)形成的序列称为 斐波那契数列 。该数列由 0
和 1
开始,后面的每一项数字都是前面两项数字的和。也就是:
1 2
| F(0) = 0,F(1) = 1 F(n) = F(n - 1) + F(n - 2),其中 n > 1
|
给定 n
,请计算 F(n)
。
思路
直观思路:递归求解,只需记录前一个元素和前前一个元素。
时间优化:矩阵快速幂。
动态规划
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Solution { public int fib(int n) { int a=0,b=1,c=0; for(int i=0;i<n;i++){ a=b; b=c; c=a+b; } return c; } }
|
矩阵快速幂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| class Solution { public int fib(int n) { if(n<2){ return n; } int[][] res=new int[][]{{1,1},{1,0}}; int[][] ans=quickPow(res,n-1); return ans[0][0]; } public int[][] quickPow(int[][] p,int n){ int[][] ret=new int[][]{{1,0},{0,1}}; while(n>0){ if((n&1)==1){ ret=multiply(ret,p); } n>>=1; p=multiply(p,p); } return ret; } public int[][] multiply(int[][] a,int[][] b){ int[][] ans=new int[2][2]; for(int i=0;i<2;i++){ for(int j=0;j<2;j++){ ans[i][j]=a[i][0]*b[0][j]+a[i][1]*b[1][j]; } } return ans; } }
|
1.2 Pow(x,n)
实现 pow(x, n) ,即计算 x
的整数 n
次幂函数(即,xn
)。
思路
矩阵快速幂,若指数为偶数,那么x*x
;若为奇数,那么x*x*ans
,最终ans
即为所求
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class Solution { public double myPow(double x, int n) { double ans=1.0; long t=n; if(t<0){ t=-t; x=1/x; } while(t>0){ if((t&1)==1){ ans*=x; } t>>=1; x*=x; } return ans; } }
|
1.3 反转链表
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
思路
按照节点依次反转链表。
递归
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
class Solution { public ListNode reverseList(ListNode head) { if(head==null||head.next==null){ return head; } ListNode root=reverseList(head.next); head.next.next=head; head.next=null; return root; } }
|
迭代
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
class Solution { public ListNode reverseList(ListNode head) { ListNode cur=head,pre=null; while(cur!=null){ ListNode next=cur.next; cur.next=pre; pre=cur; cur=next; } return pre; } }
|
1.4 回文链表
给你一个单链表的头节点 head
,请你判断该链表是否为回文链表。如果是,返回 true
;否则,返回 false
。
思路
- 先找到前半部分链表的尾节点
- 反转后半部分链表
- 判断是否回文
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
class Solution { public boolean isPalindrome(ListNode head) { if(head==null) return true; ListNode tail=findTail(head); ListNode reverseNode=reverse(tail.next); ListNode p=head; ListNode q=reverseNode; while(q!=null){ if(p.val!=q.val){ return false; } p=p.next; q=q.next; } return true; } public ListNode findTail(ListNode root){ ListNode slow=root; ListNode fast=root; while(fast.next!=null&&fast.next.next!=null){ slow=slow.next; fast=fast.next.next; } return slow; } public ListNode reverse(ListNode head){ ListNode cur=head,pre=null; while(cur!=null){ ListNode next=cur.next; cur.next=pre; pre=cur; cur=next; } return pre; } }
|
1.5 两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
思路
递归模拟。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
class Solution { public ListNode swapPairs(ListNode head) { if(head==null||head.next==null){ return head; } ListNode root=head.next; head.next=swapPairs(root.next); root.next=head; return root; } }
|
2. 复杂递归算法设计
2.1 螺旋矩阵 II
给你一个正整数 n
,生成一个包含 1
到 n2
所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
。
思路
按照题意进行模拟,注意四个方向。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class Solution { public int[][] generateMatrix(int n) { int[][] cnt=new int[n][n]; int left=0,right=n-1,top=0,bottom=n-1; int num=1; while(true){ for(int i=left;i<=right;i++) cnt[top][i]=num++; if(++top>bottom) break; for(int i=top;i<=bottom;i++) cnt[i][right]=num++; if(--right<left) break; for(int i=right;i>=left;i--) cnt[bottom][i]=num++; if(--bottom<top) break; for(int i=bottom;i>=top;i--) cnt[i][left]=num++; if(++left>right) break; } return cnt; } }
|
2.2 N 皇后
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将 n
个皇后放置在 n×n
的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n
,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q'
和 '.'
分别代表了皇后和空位。
思路
经典回溯算法问题,n = 8 时便是著名的八皇后问题。
依次判断当前位置是否有效,以决定是否将当前位置加入棋盘中。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| class Solution { private List<List<String>> res=new ArrayList<>(); private List<StringBuilder> tmp=new ArrayList<>(); private int n; public List<List<String>> solveNQueens(int n) { this.n=n; for(int i=0;i<n;i++){ StringBuilder cnt=new StringBuilder(); for(int j=0;j<n;j++){ cnt.append('.'); } tmp.add(cnt); } backtrack(0); return res; } public void backtrack(int row){ if(row==n){ List<String> hep=tmp.stream().map(s -> s.toString()).collect(Collectors.toList()); res.add(hep); return; } for(int i=0;i<n;i++){ if(!isValid(row,i)){ continue; } tmp.get(row).setCharAt(i,'Q'); backtrack(row+1); tmp.get(row).setCharAt(i,'.'); } } public boolean isValid(int row,int col){ for(int i=row-1,j=col-1;i>=0&&j>=0;i--,j--){ if(tmp.get(i).charAt(j)=='Q'){ return false; } } for(int i=row-1,j=col;i>=0;i--){ if(tmp.get(i).charAt(j)=='Q'){ return false; } } for(int i=row-1,j=col+1;i>=0&&j<n;j++,i--){ if(tmp.get(i).charAt(j)=='Q'){ return false; } } return true; } }
|