劍指Offer系列之題16~題20

  • 2020 年 4 月 12 日
  • 筆記

16.反轉鏈表

輸入一個鏈表,反轉鏈表後,輸出新鏈表的表頭。

從前往後,依次將當前節點的next指向前結點。用多個變數存儲當前節點,下一節點,前結點。


public class Solution {      public ListNode ReverseList(ListNode head) {          if(head==null)              return null;          //從頭開始,依次將節點的next指向前一個結點          ListNode prev=null;          ListNode cur=head;          ListNode follow=null;          while(cur.next!=null){              follow=cur.next;//獲得當前結點的下個節點              cur.next=prev;//將當前節點的next指向前一個結點              prev=cur;//保存當前結點作為前結點              cur=follow;          }          cur.next=prev;          return cur;      }  }  

17.合併兩個排序的鏈表

輸入兩個單調遞增的鏈表,輸出兩個鏈表合成後的鏈表,當然我們需要合成後的鏈表滿足單調不減規則。

基本:遍歷兩鏈表,當l2中元素小於l1時,將其加入l1,直到末尾。或者新建一個鏈表,將小的依次加入該鏈表


1.暴力:

/*添加至list1*/  public class Solution {      public ListNode Merge(ListNode list1,ListNode list2) {          //結果要求是單調遞增          //錯誤輸入的判斷          if(list1==null && list2 ==null)              return null;          if(list1== null)              return list2;          if(list2==null)              return list1;          ListNode p1=list1;          ListNode p2=list2;          ListNode temp1=null;//暫存兩鏈表的結點          ListNode temp2=null;          //依次從鏈表頭開始判斷          while(p1!=null && p2!=null ){              while(p1!=null && p1.val<p2.val){//當l1的結點小於l2時,將l1結點右移                  temp1=p1;//記錄當前結點,便於後續插入                  p1=p1.next;              }//直到p1.val >= p2.val或p1.next==null              if(p1==null){//若l1已到末尾,則將l2的結點接到l1末尾後                  temp1.next=p2;                  return list1;              }              temp2=new ListNode(p2.val);//list2的結點移到list1              temp2.next=p1;              if(temp1!=null)//判斷是否是添加到l1的頭部                  temp1.next=temp2;              else{//是則讓list1頭節點變為temp2                  list1=temp2;              }              p1=temp2;//該結點一定比l2的下一節點小,所以temp1下一步一定會切換              if(p2.next==null)//如果l2遍歷完畢                  break;              p2=p2.next;//p2右移          }          return list1;      }  }  

2.遞歸:

/*相當於一個新鏈表*/  public class Solution {      public ListNode Merge(ListNode list1,ListNode list2) {          //結果要求是單調遞增          //錯誤輸入的判斷          if(list1==null && list2 ==null)              return null;          if(list1== null)              return list2;          if(list2==null)              return list1;          //遞歸          if(list1.val <=list2.val){              list1.next=Merge(list1.next,list2);              return list1;          }else{              list2.next=Merge(list1,list2.next);              return list2;          }      }  }  

3.新建鏈表存儲:

public class Solution {      public ListNode Merge(ListNode list1,ListNode list2) {          //新建一個頭節點,用來存合併的鏈表。          ListNode head=new ListNode(-1);          head.next=null;          ListNode root=head;          while(list1!=null && list2!=null){              if(list1.val<list2.val){                  head.next=list1;                  head=list1;                  list1=list1.next;              }else{                  head.next=list2;                  head=list2;                  list2=list2.next;              }          }          //把未結束的鏈表連接到合併後的鏈表尾部          if(list1!=null){              head.next=list1;          }          if(list2!=null){              head.next=list2;          }          return root.next;      }  }  

18.樹的子結構 ?

輸入兩棵二叉樹A,B,判斷B是不是A的子結構。(ps:我們約定空樹不是任意一個樹的子結構)

先判斷A中根節點是否等於B根節點,相等則對兩者左右子樹進行遍歷判斷是否相等;

若根節點不等,則從A的左右子樹中尋找等於B中根節點的節點,然後判斷。

遞歸


遞歸:

public class Solution {      public boolean HasSubtree(TreeNode root1,TreeNode root2) {          if(root1 ==null || root2 == null)//輸入判斷              return false;          boolean flag=false;          //查看2的前序和中序遍歷是否屬於1          if (root1.val == root2.val){//當A的根結點等於B的根節點時,對其子樹進行遍歷判斷(遞歸)              flag=judgeSub(root1,root2);          }          if(!flag)//當A的根節點不等於B的根節點時,從根節點的左子樹中查找相等的節點              flag=HasSubtree(root1.left,root2);          if(!flag)//從根節點的右子樹中查找相等的節點              flag=HasSubtree(root1.right,root2);          return flag;      }        //根節點相等時,判斷其結構是否相等      public boolean judgeSub(TreeNode root1,TreeNode root2){          if(root2==null)//若B節點為空,則證明該節點前結構屬於A,因為前面的已證過相等,不然不會走到該步              return true;          if(root1==null)//若A節點為空,則兩者結構不等              return false;          if(root1.val != root2.val)              return false;          return judgeSub(root1.left,root2.left) && judgeSub(root1.right,root2.right);//遞歸判斷左右子樹是否相等      }  }  

19.二叉樹的鏡像

操作給定的二叉樹,將其變換為源二叉樹的鏡像。
輸入描述:

二叉樹的鏡像定義:       源二叉樹          8         /          6   10       /   /       5  7 9 11      鏡像二叉樹          8         /          10   6       /   /       11 9 7  5  

遞歸處理左右子樹

遞歸:

public class Solution {      public void Mirror(TreeNode root) {          if(root!=null){              //根節點不變,左右子樹交換位置              //遞歸              if(root.left!=null ){//若根節點左右子樹非空,則將左右子樹進行翻轉                  Mirror(root.left);              }              if(root.right!=null)                  Mirror(root.right);              TreeNode temp=root.left;              root.left=root.right;              root.right=temp;          }      }  }  

20.順時針列印矩陣

輸入一個矩陣,按照從外向里以順時針的順序依次列印出每一個數字,例如,如果輸入如下4 X 4矩陣: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 則依次列印出數字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10。

找到每次遍歷的起始點,然後以此進行判斷每次遍歷的邊界。(每次遍歷前一定要判斷前置條件)


1.暴力:

import java.util.ArrayList;  public class Solution {      private ArrayList<Integer> result=new ArrayList<>();      public ArrayList<Integer> printMatrix(int [][] matrix) {          if(matrix==null || matrix.length==0)              return null;          int rows=matrix.length;          int cols=matrix[0].length;          int start=0;          //找出每一圈的起始點。即左上角的點,(0,0) (1,1)等          while(rows>start*2 && cols>start*2){              int endCol=cols-1-start;//該次遍歷時最右邊列的坐標              int endRow=rows-1-start;//該次遍歷時最下邊行的坐標                for(int i=start;i<=endCol;++i){//列印第一行                  result.add(matrix[start][i]);              }              if(start<endRow){//滿足才有一列可以列印,否則一行直接列印完畢                  for(int i=start+1;i<=endRow;++i){//列印最後一列                      result.add(matrix[i][endCol]);                  }              }              if(start<endCol && start<endRow){//滿足才有最後一行可以列印                  for(int i=endCol-1;i>=start;--i){//列印最後一行                      result.add(matrix[endRow][i]);                  }              }              if(start<endCol && start< endRow-1){//滿足時才會在最後一行列印完畢後仍有上面的行                  for(int i=endRow-1;i>start;--i){//列印第一列                      result.add(matrix[i][start]);                  }              }              start++;          }          return result;      }    }  

如有錯誤,歡迎指正

Tags: