劍指Offer第三週
35.反轉鏈表
定義一個函數,輸入一個鏈表的頭結點,反轉該鏈表並輸出反轉後鏈表的頭結點。
思考題:
- 請同時實現迭代版本和遞歸版本。
樣例
輸入:1->2->3->4->5->NULL
輸出:5->4->3->2->1->NULL
pre,cur,next,暴力翻轉
pre = null,cur = pre, pre = cur,cur = next; 翻轉 模板
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null, cur = head;
while(cur != null){
ListNode next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
}
36.合併兩個排序的鏈表
輸入兩個遞增排序的鏈表,合併這兩個鏈表並使新鏈表中的結點仍然是按照遞增排序的。
樣例
輸入:1->3->5 , 2->4->5
輸出:1->2->3->4->5->5
沒什麼好說的,歸併排序的思想
class Solution {
public ListNode merge(ListNode l1, ListNode l2) {
ListNode dump = new ListNode(-1);
ListNode head = dump;
while(l1 != null && l2 != null){
if(l1.val <= l2.val){
dump.next = l1;
dump = dump.next;
l1 = l1.next;
}else{
dump.next = l2;
dump = dump.next;
l2 = l2.next;
}
}
if(l1 != null) dump.next = l1;
else dump.next = l2;
return head.next;
}
}
37.樹的子結構
輸入兩棵二叉樹A,B,判斷B是不是A的子結構。
我們規定空樹不是任何樹的子結構。
樣例
樹A:
8
/ \
8 7
/ \
9 2
/ \
4 7
樹B:
8
/ \
9 2
返回 true ,因爲B是A的子結構。
寫一個helper函數,判斷兩棵樹是否相等。遞歸判斷每一個節點
class Solution {
public boolean hasSubtree(TreeNode p, TreeNode q) {
if(p == null || q == null)return false;
return helper(p,q) || hasSubtree(p.left,q) || hasSubtree(p.right,q);
}
public boolean helper(TreeNode p, TreeNode q){
if(p == null && q == null)return true;
if(p == null)return false;
if(q == null)return true;
if(p.val != q.val)return false;
return helper(p.left,q.left) && helper(p.right,q.right);
}
}
38.二叉樹的鏡像
輸入一個二叉樹,將它變換爲它的鏡像。
樣例
輸入樹:
8
/ \
6 10
/ \ / \
5 7 9 11
[8,6,10,5,7,9,11,null,null,null,null,null,null,null,null]
輸出樹:
8
/ \
10 6
/ \ / \
11 9 7 5
[8,10,6,11,9,7,5,null,null,null,null,null,null,null,null]
對每一個節點的左右子樹進行交換
class Solution {
public void mirror(TreeNode root) {
if(root == null)return ;
mirror(root.left);
mirror(root.right);
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
}
}
39.對稱的二叉樹
請實現一個函數,用來判斷一棵二叉樹是不是對稱的。
如果一棵二叉樹和它的鏡像一樣,那麼它是對稱的。
樣例
如下圖所示二叉樹[1,2,2,3,4,4,3,null,null,null,null,null,null,null,null]爲對稱二叉樹:
1
/ \
2 2
/ \ / \
3 4 4 3
如下圖所示二叉樹[1,2,2,null,4,4,3,null,null,null,null,null,null]不是對稱二叉樹:
1
/ \
2 2
\ / \
4 4 3
拿樹的左邊和右邊比,右邊和左邊比
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null)return true;
return helper(root.left,root.right);
}
public boolean helper(TreeNode p,TreeNode q){
if(p == null && q == null)return true;
if(p == null || q == null)return false;
if(p.val == q.val) return helper(p.left,q.right) && helper(p.right,q.left);
return false;
}
}
40.順時針打印矩陣
輸入一個矩陣,按照從外向裏以順時針的順序依次打印出每一個數字。
樣例
輸入:
[
[1, 2, 3, 4],
[5, 6, 7, 8],
[9,10,11,12]
]
輸出:[1,2,3,4,8,12,11,10,9,5,6,7]
直接模擬
class Solution {
public int[] printMatrix(int[][] matrix) {
int r = matrix.length;
if(r <= 0)return new int[0];
int c = matrix[0].length,i = 0, j = 0,cnt = 0;
boolean[][] vis = new boolean[r][c];
int total = r * c;
int[] res = new int[total];
while(cnt < total){
// 右
while(j < c && !vis[i][j]){
res[cnt++] = matrix[i][j];
vis[i][j] = true;
j++;
}
j--;i++;
// 下
while(i < r && !vis[i][j]){
res[cnt++] = matrix[i][j];
vis[i][j] = true;
i++;
}
i--;j--;
// 左
while(j >= 0 && !vis[i][j]){
res[cnt++] = matrix[i][j];
vis[i][j] = true;
j--;
}
j++;i--;
// 上
while(i >= 0 && !vis[i][j]){
res[cnt++] = matrix[i][j];
vis[i][j] = true;
i--;
}
i++;j++;
}
return res;
}
}
d 爲方向,下一個點不能走則換方向
class Solution {
public int[] printMatrix(int[][] matrix) {
int r = matrix.length;
if(r <= 0)return new int[0];
int c = matrix[0].length,cnt = 0,d = 0;
boolean[][] vis = new boolean[r][c];
int[] res = new int[r * c],dx = {0,1,0,-1}, dy = {1,0,-1,0};
int x = 0,y = 0;
for(int i = 0; i < r * c; i ++){
res[cnt++] = matrix[x][y];
vis[x][y] = true;
int a = x + dx[d], b = y + dy[d];
if(a < 0 || a >= r || b < 0 || b >= c || vis[a][b]){
d = (d + 1) % 4;
a = x + dx[d]; b = y + dy[d];
}
x = a; y = b;
}
return res;
}
}
41.包含min函數的棧
設計一個支持push,pop,top等操作並且可以在O(1)時間內檢索出最小元素的堆棧。
- push(x)–將元素x插入棧中
- pop()–移除棧頂元素
- top()–得到棧頂元素
- getMin()–得到棧中最小元素
樣例
MinStack minStack = new MinStack();
minStack.push(-1);
minStack.push(3);
minStack.push(-4);
minStack.getMin(); --> Returns -4.
minStack.pop();
minStack.top(); --> Returns 3.
minStack.getMin(); --> Returns -1.
設置一個min,存儲最小的值,當min要發生改變時,將這個min存入stack,方便min被pop時,取出前一個min;
class MinStack {
Stack<Integer> stack;
Integer min;
/** initialize your data structure here. */
public MinStack() {
stack = new Stack<>();
min = Integer.MAX_VALUE;
}
public void push(int x) {
if(x <= min){
stack.push(min);
min = x;
stack.push(x);
}else stack.push(x);
}
public void pop() {
Integer cur = stack.pop();
if(cur == min){
min = stack.pop();
}
}
public int top() {
return stack.peek();
}
public int getMin() {
return min;
}
}
42. 棧的壓入、彈出序列
輸入兩個整數序列,第一個序列表示棧的壓入順序,請判斷第二個序列是否可能爲該棧的彈出順序。
假設壓入棧的所有數字均不相等。
例如序列1,2,3,4,5是某棧的壓入順序,序列4,5,3,2,1是該壓棧序列對應的一個彈出序列,但4,3,5,1,2就不可能是該壓棧序列的彈出序列。
注意:若兩個序列長度不等則視爲並不是一個棧的壓入、彈出序列。若兩個序列都爲空,則視爲是一個棧的壓入、彈出序列。
樣例
輸入:[1,2,3,4,5]
[4,5,3,2,1]
輸出:true
當前只有兩個操作:
- 當棧頂元素與其相等時,pop
- 佛則入棧
如果棧頂不相等也Pop,的話,序列就不對了;
class Solution {
public boolean isPopOrder(int[] push,int[] pop) {
if(push.length != pop.length)return false;
Stack<Integer> stack = new Stack<>();
int i = 0;
for(Integer num : push){
stack.push(num);
while(!stack.isEmpty() && stack.peek() == pop[i]){
stack.pop();
i ++;
}
}
return stack.isEmpty();
}
}
43.不分行從上往下打印二叉樹
從上往下打印出二叉樹的每個結點,同一層的結點按照從左到右的順序打印。
樣例
輸入如下圖所示二叉樹[8, 12, 2, null, null, 6, null, 4, null, null, null]
8
/ \
12 2
/
6
/
4
輸出:[8, 12, 2, 6, 4]
簡單層次遍歷
class Solution {
public List<Integer> printFromTopToBottom(TreeNode root) {
if(root == null) return new ArrayList<Integer>();
List<Integer> list = new ArrayList<Integer>();
ArrayDeque<TreeNode> q = new ArrayDeque<TreeNode>();
q.offer(root);
list.add(root.val);
while(!q.isEmpty()){
int count = q.size();
for(int i = 0; i < count; i ++){
TreeNode cur = q.poll();
if(cur.left != null){
list.add(cur.left.val);
q.offer(cur.left);
}
if(cur.right != null){
list.add(cur.right.val);
q.offer(cur.right);
}
}
}
return list;
}
}
44.分行從上往下打印二叉樹
從上到下按層打印二叉樹,同一層的結點按從左到右的順序打印,每一層打印到一行。
樣例
輸入如下圖所示二叉樹[8, 12, 2, null, null, 6, null, 4, null, null, null]
8
/ \
12 2
/
6
/
4
輸出:[[8], [12, 2], [6], [4]]
跟上一題一模一樣,寬搜即可,每個cout代表每一層的個數
class Solution {
public List<List<Integer>> printFromTopToBottom(TreeNode root) {
if(root == null) return new ArrayList<>();
List<List<Integer>> list = new ArrayList<>();
ArrayDeque<TreeNode> q = new ArrayDeque<TreeNode>();
q.offer(root);
ArrayList<Integer> pp = new ArrayList<Integer>();pp.add(root.val);
list.add(pp);
while(!q.isEmpty()){
int count = q.size();
ArrayList<Integer> temp = new ArrayList<Integer>();
for(int i = 0; i < count; i ++){
TreeNode cur = q.poll();
if(cur.left != null){
temp.add(cur.left.val);
q.offer(cur.left);
}
if(cur.right != null){
temp.add(cur.right.val);
q.offer(cur.right);
}
}
if(temp.size() > 0)list.add(temp);
}
return list;
}
}
45.之字形打印二叉樹
請實現一個函數按照之字形順序從上向下打印二叉樹。
即第一行按照從左到右的順序打印,第二層按照從右到左的順序打印,第三行再按照從左到右的順序打印,其他行以此類推。
樣例
輸入如下圖所示二叉樹[8, 12, 2, null, null, 6, 4, null, null, null, null]
8
/ \
12 2
/ \
6 4
輸出:[[8], [2, 12], [6, 4]]
同理,在上一題的基礎上,加一個flag標誌位,代表當前從左往右,還是從右往左;
class Solution {
public List<List<Integer>> printFromTopToBottom(TreeNode root) {
if(root == null) return new ArrayList<>();
List<List<Integer>> list = new ArrayList<>();
ArrayDeque<TreeNode> q = new ArrayDeque<TreeNode>();
q.offer(root);
ArrayList<Integer> pp = new ArrayList<Integer>();pp.add(root.val);
list.add(pp);
boolean f = false;
while(!q.isEmpty()){
int count = q.size();
ArrayList<Integer> temp = new ArrayList<Integer>();
for(int i = 0; i < count; i ++){
if(f){
TreeNode cur = q.pollFirst();
if(cur.left != null){
temp.add(cur.left.val);
q.offerLast(cur.left);
}
if(cur.right != null){
temp.add(cur.right.val);
q.offerLast(cur.right);
}
}else{
TreeNode cur = q.pollLast();
if(cur.right != null){
temp.add(cur.right.val);
q.offerFirst(cur.right);
}
if(cur.left != null){
temp.add(cur.left.val);
q.offerFirst(cur.left);
}
}
}
f = !f;
if(temp.size() > 0)list.add(temp);
}
return list;
}
}
class Solution {
public List<List<Integer>> printFromTopToBottom(TreeNode root) {
List res = new ArrayList();
List<TreeNode> q = new ArrayList<>();
if(root != null)q.add(root);
boolean reverse = false;
while(q.size() > 0){
List cur_v = new ArrayList();
List cur_q = new ArrayList();
for(TreeNode t : q){
cur_v.add(t.val);
if(t.left != null)cur_q.add(t.left);
if(t.right != null)cur_q.add(t.right);
}
q = cur_q;
if(reverse)Collections.reverse(cur_v);
reverse = !reverse;
res.add(cur_v);
}
return res;
}
}