1. 程式人生 > >劍指Offer演算法題JAVA版13-20題(全是個人寫的非官方,只供參考和自己複習,測試用例都通過了。)

劍指Offer演算法題JAVA版13-20題(全是個人寫的非官方,只供參考和自己複習,測試用例都通過了。)

13.調整陣列順序使奇數位於偶數前面

輸入一個整數陣列,實現一個函式來調整該陣列中數字的順序,使得所有的奇數位於陣列的前半部分,所有的偶數位於位於陣列的後半部分,並保證奇數和奇數,偶數和偶數之間的相對位置不變。

(思路:是一個類似與快速排序,的思路,但快速排序是不穩定的。要保證,偶數和基數的相對位置穩定)

 public void reOrderArray(int [] array) {
		        int n=0;//指向要被交換的位置,始終位於偶數串的第一位
		        int k=0;//記錄連續的偶數串長度
		        for(int i=0;i<array.length;i++){//其中i就是遍歷整個陣列,走到偶數,就繼續往前走,並記錄走過偶數的個數,遇到奇數就將該基數,放到n所在位置,然後將整個偶數串後移一位。
		        	if((array[i]&1)==0){//計算遍歷到i位置,一共有多少個偶數
		        		k++;//
		        	}
		        	if((array[i]&1)==1){//當為級數
		        			int t=array[i];
		        			int p=k;
		        			while(p>0){//偶數串總體移動,保持相對位置不變
		        				array[n+p]=array[n+p-1];//整個偶數串,向後移。
		        				p--;
		        			}
		        			array[n]=t;//把奇數和需要被交換的位置
		        			n++;//被交換位置向前移動。
		        		}
		    }
		  }
14.連結串列中倒數第k個結點

輸入一個連結串列,輸出該連結串列中倒數第k個結點。

(思路很簡單,兩個指標都指向頭節點,然後讓其中一個向前跑k-1次,然後,後邊的指標開始跟著跑,直到前面指標的next 是空,則後面指標的位置就是倒數第k個元素)

 public ListNode FindKthToTail(ListNode head,int k) {
			 ListNode p=head;//後起步的指標
			 ListNode pre=head;//先起步的指標
			if(k<=0)return null;//非法的k
			while(k>1&&pre!=null){//讓pre先走k-1步,
				pre=pre.next;
					k--;
			}
			if(pre==null){//整個鏈不足k個,返回空
				return null;
			}else{
			while(pre.next!=null){//pre走k-1之後,p和pre一起走。
				pre=pre.next;
				p=p.next;
			}
			return p;
			}
		    
		 }

15.反轉連結串列

輸入一個連結串列,反轉連結串列後,輸出連結串列的所有元素。

15.1(思路:將整個鏈放入一個棧,放完之後,出棧,然後根據出棧的順序重新連線一條鏈就好了)

 public ListNode ReverseList(ListNode head) {
			 	Stack<ListNode> stack=new Stack<ListNode>();
			 	while(head!=null){//全部放入棧
			 		stack.push(head);
			 		head=head.next;
			 	}
			 	if(!stack.isEmpty()){//棧不為空的情況下
			 		ListNode last=stack.pop();//last指標指向第一個出<span style="line-height: 25.2px; font-family: arial, STHeiti, 'Microsoft YaHei', 宋體;">棧</span>的元素
			 		ListNode first=last;//新的first指標也指向第一個出棧的元素
			 		while(!stack.isEmpty()){
			 			last.next=stack.pop();//last的下一個元素等於下一個彈出的元素
			 			last=last.next;//last指標指向最新的彈出的元素
			 		}
			 		last.next=null;//迴圈之後,last位於最後一個元素,將最後一個元素的next置為空。
			 		return first;//返回新連結串列的頭
			 	}else{//棧為空,返回空
			 		return null;
			 	}
		    }

15.2用三個指標來,來操作,這樣節省空間。

 public ListNode ReverseList(ListNode head) {
			 	ListNode pre=null;
			 	ListNode hnext=null;
			 	while(head!=null){
			 		hnext=head.next;
			 		head.next=pre;
			 		pre=head;
			 		head=hnext;
			 	}
			 	return pre;
		    }

16.合併兩個排序的連結串列

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

16.1非遞迴方法

(思路:思路較簡單)

 public ListNode Merge(ListNode list1,ListNode list2) {
         ListNode list3=null;
	   ListNode listHead=null;
	   if(list1!=null&list2!=null){
	   if(list1.val<=list2.val){//將返回連結串列的頭指標放在兩個連結串列中值小的頭上。
		   list3=new ListNode(list1.val);
		   listHead=list3;
		   list1=list1.next;
		   
	   }else if(list2.val<list1.val){
		   list3=new ListNode(list2.val);
		   listHead=list3;
		   list2=list2.next;
	   }
	   //一次迴圈,兩個連結串列元素一次比較,值較小的接到,返回連結串列後面,知道其中一個連結串列走完
	   while(list1!=null&&list2!=null){
		   if(list1.val<=list2.val){
			   list3.next=list1;
			   list3=list3.next;
			   list1=list1.next;
		   }else{
			   list3.next=list2;
			   list3=list3.next;
			   list2=list2.next;
		   }
		  
	   }
	   if(list1==null){//將沒有遍歷完的連結串列的剩餘部分接到,返回連結串列的後面
		   list3.next=list2;
	   }else if(list2==null){
		   list3.next=list1;
	   }
	   return listHead;
	   }else if(list1==null&&list2!=null){
		  listHead=list2;
	   }else if(list2==null&&list1!=null){
		   listHead=list1;
	   }
	  return listHead;
    }
16.2遞迴的方法
 public ListNode Merge(ListNode list1,ListNode list2) {
			 if(list1==null){
				 return list2;
			 }else 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;
		        }
		    }

17.樹的子結構

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

public boolean HasSubtree(TreeNode root1,TreeNode root2) {
			 if(root1==null||root2==null){
				 return false;
			 }
			if(root1.val==root2.val){//一旦當前節點相同,便呼叫<pre name="code" class="java" style="color: rgb(51, 51, 51); font-size: 14px; line-height: 22.4px;">isChildTree()方法,檢視root2是否是root1的子樹
boolean result=Solution.isChildTree(root1, root2);if(!result){
boolean res1=HasSubtree(root1.right,root2);boolean res2=HasSubtree(root1.left, root2);return res2||res1;}else{return true;}}else{boolean res1=HasSubtree(root1.right,root2);boolean res2=HasSubtree(root1.left, root2);return res2||res1;} } public static boolean isChildTree(TreeNode root1,TreeNode root2){// 該方法用來判斷 兩個相同根的樹,root2是否是root1的子樹 boolean result=false; if(root2==null){ return true; }else if(root1==null){ return false; } if(root1.val!=root2.val){ return false; }else{boolean res1= isChildTree(root1.right,root2.right);boolean re2=isChildTree(root1.left, root2.left);result=res1&&re2;return result; } } 18.二叉樹的映象 操作給定的二叉樹,將其變換為源二叉樹的映象。 
輸入描述:
二叉樹的映象定義:源二叉樹 
    	    8
    	   /  \
    	  6   10
    	 / \  / \
    	5  7 9 11
    	映象二叉樹
    	    8
    	   /  \
    	  10   6
    	 / \  / \
    	11 9 7  5
 public void Mirror(TreeNode root) {
			 	if(root!=null){
			 		Mirror(root.left);
			 		Mirror(root.right);
			 		TreeNode temp=root.left;
			 		root.left=root.right;
			 		root.right=temp;
			 	}
		        	
		        
		    }

19.順時針列印矩陣

輸入一個矩陣,按照從外向裡以順時針的順序依次打印出每一個數字,例如,如果輸入如下矩陣: 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.

	public ArrayList<Integer> printMatrix(int [][] matrix) {
			ArrayList<Integer> list=new ArrayList<Integer>();
		       if(matrix.length==0){
		    	   return null;
		       }else if(matrix.length==1){
		    	  for(int j=0;j<matrix[0].length;j++){
		    		  list.add(matrix[0][j]);
		    	  }
		       }else if(matrix[0].length==1){
		    	   for(int i=0;i<matrix.length;i++){
		    		   list.add(matrix[i][0]);
		    	   }
		       }else{
		    	   int k=matrix.length<=matrix[0].length?matrix.length:matrix[0].length;
		    	   double t=((double)k)/2;
		    	   int x=0;
		    	   while(t>0){
		    		   if(k-x*2>1){
		    		for(int i=x;i<matrix[0].length-x-1;i++){
		    			list.add(matrix[x][i]);
		    		}
		    		for(int i=x;i<matrix.length-x-1;i++){
		    			list.add(matrix[i][matrix[0].length-x-1]);
		    		}
		    		for(int i=matrix[0].length-x-1;i>x;i--){
		    			list.add(matrix[matrix.length-x-1][i]);
		    		}
		    		for(int i=matrix.length-x-1;i>x;i--){
		    			list.add(matrix[i][x]);
		    		}
		    		x++;
		    		t--;
		    		   }else{
		    			   if(matrix.length>=matrix[0].length){
		    				   for(int i=x;i<matrix.length-x;i++){
		    					   list.add(matrix[i][x]);
		    				   }
		    				
		    			   }else{
		    				   for(int i=x;i<matrix[0].length-x;i++){
		    					   list.add(matrix[x][i]);
		    				   }
		    				
		    			   }
		    			   x++;
		   		    		t--;
		    		   }
		    	   }

		    	  
		       }
		       return list;
	    }
		

20.包含min函式的棧

定義棧的資料結構,請在該型別中實現一個能夠得到棧最小元素的min函式。

(思路:一個min棧用來儲存當前最小的數,該棧棧頂始終是當前最小。出棧操作的時候,判斷當前最小元素被彈出,若當前最小彈出,那麼min棧也彈出,此時當前最小,依舊是min棧的棧頂)

public class Solution {
		  Stack<Integer> stack=new Stack<Integer>();
		  Stack<Integer> min =new Stack<Integer>();
	    public void push(int node) {
	    	int minn=Integer.MAX_VALUE;
	    	if(!min.isEmpty()){
	    		minn=min.peek();
	    	}
	        stack.push(node);
	        if(node<=minn){
	        	minn=node;
	        	min.push(node);
	        }
	       
	    }
	    public void pop() {
	      int i=stack.pop();
	      if(i==min.peek()){
	    	  min.pop();
	      }
	      
	    }
	    
	    public int top() {
	        return  stack.peek();
	    }
	    
	    public int min() {
	      return min.peek();
	      
	    }
		
			
		}