劍指offer編程題java實現(正在更新)


面試題三:查找二維數組中元素問題

 

public static void main(String[] args){
         int[][] num = {{1,2,8,9},{2,4,9,12},{4,7,10,13},{6,8,11,15}};
        search(num,7);
        
     }
      public static void search(int[][] arr,int target){
          int rows = arr.length;
          int columns = arr[0].length;
          int row = 0;
          int column = columns-1;
          
          while(row<=rows&&column>=0){
          if(target==arr[row][column]){
              System.out.println(target+"在第"+row+"行,第"+column+"列");
              break;
            }
          if(target>arr[row][column]){
              row++;
          }
          if(target<arr[row][column]){
              column--;
          }
         }
      }

 

面試題四:替換字符串中的空格

延伸:1.合並兩個字符串     2.兩個有序數組,將一個插入到另一個,並保證有序。    從后面開始會減少元素移動的次數?

 public static void main(String[] args){
         int[][] num = {{1,2,8,9},{2,4,9,12},{4,7,10,13},{6,8,11,15}};
          String str = "we are happy";
          replaceBlank(str);
         
     }       
     public static void replaceBlank(String str){
         
         char[] charOld = str.toCharArray();
         char[] charNew = new char[100];
         for(int j = 0;j<charOld.length;j++){
             charNew[j] = charOld[j];
         }
         int blank = 0;
          for(int i = 0;i<charNew.length;i++){
              if(charNew[i]==' '){
                  blank++;
              }
          }
          int lengthFront = charOld.length-1;
          
          int lengthBack = charOld.length+2*blank-1;
          
          while(lengthFront>=0&&lengthBack>=0){
              if(charNew[lengthFront]!=' '){
                  charNew[lengthBack--] = charNew[lengthFront];
              }
              else 
              {
                  charNew[lengthBack--] = '0';
                  charNew[lengthBack--] = '2';
                  charNew[lengthBack--] = '%';
                  lengthFront--;
              }
              lengthFront--;
          }
          System.out.println(charNew);
          
          
     }

 面試題5.從尾到頭打印鏈表(利用棧或遞歸來實現)

構建鏈表

public class ListNode {
    private int value;
    private ListNode next;
    public ListNode(int value){
        this.value = value;
    }
    
    public ListNode(int value,ListNode next){
        this.value = value;
        this.next = next;
    }
    
    public void setValue(int value){
        this.value = value;
    }
    
    public int getValue(ListNode node){
        return node.value;
    }
    public void setNext(ListNode next){
        this.next = next;
    }
    public ListNode getNext(){
        return this.next;
    }

}

 

Stack s = new Stack();     棧                                                 public static void method(head){    遞歸,但是鏈表長度較長時就不要用

ListNode p = head;                                                                      if(head!=null){

while(p!=null){                                                                                 if(head.getNext()!=null){

  stack.push(p.getValue());                                                                      method(head.getNext);

  p=p.getNext();                                                                                }

}                                                                                                  System.out.println(head.getValue());

while(!s.isEmpty){                                                                    }

System.out.println(s.pop());                                             }

}

 

面試題六:根據前序和中序輸出構造二叉樹

建二叉樹

public class BinaryTreeNode {

    private int value;
    private BinaryTreeNode left;
    private BinaryTreeNode right;
    public BinaryTreeNode(int value){
        this.value = value;
    }
    public BinaryTreeNode(int value,BinaryTreeNode left,BinaryTreeNode right){
        this.value = value;
        this.left = left;
        this.right = right;
    }
    public int getValue( ){
        return this.value;
    }
    public void setValue(BinaryTreeNode node){
        this.value = value;
    }
    public void  setLeft(BinaryTreeNode node){
        this.left = node;
    }
    public void  setRight(BinaryTreeNode node){
        this.right = node;
    }
    public BinaryTreeNode getLeft( ){
        return this.left;
    }
    public BinaryTreeNode getRight( ){
        return this.right;
    }
}

 

 根據前序找根節點,然后判斷根節點在中序輸出中的位置,根節點左邊的就是左子樹,右邊的就是右子樹,然后遞歸調用此方法。

public static void main(String[] args){
         int[][] num = {{1,2,8,9},{2,4,9,12},{4,7,10,13},{6,8,11,15}};
         int[] frontOrder = {1,2,4,7,3,5,6,8};
         int[] inOrder = {4,7,2,1,5,3,8,6};
         BinaryTreeNode root =BinaryTree(frontOrder,inOrder);
         printPostOrder(root);
          
     }       
     public static void printPostOrder(BinaryTreeNode root){
         if(root!=null){
             printPostOrder(root.getLeft( ));
             printPostOrder(root.getRight( ));
             System.out.println(root.getValue());
         }
     }
      public static BinaryTreeNode BinaryTree(int[] frontOrder,int[] inOrder){
          BinaryTreeNode root = new BinaryTreeNode(frontOrder[0]);
          root.setLeft(null);
          root.setRight(null);
          
          int leftLength = 0;
          for(int i =0;i<inOrder.length;i++){
              if(inOrder[i]==root.getValue( )){
                  break;
              }else{
                  leftLength++;
              }
          }
          int rightLength = inOrder.length-leftLength-1;
          
          if(leftLength>0){
             int[] leftFrontOrder = new int[leftLength];
             int[] leftInorder = new int[leftLength];
             for(int j = 0;j<leftLength;j++){
                 leftFrontOrder[j] = frontOrder[j+1];
                 leftInorder[j] = inOrder[j];
             }
             BinaryTreeNode leftRoot = BinaryTree(leftFrontOrder,leftInorder);
             root.setLeft(leftRoot);
          }
          if(rightLength>0){
                 int[] rightFrontOrder = new int[rightLength];
                 int[] rightInorder = new int[rightLength];
                 for(int k = 0;k<rightLength;k++){
                     rightFrontOrder[k] = frontOrder[k+1+leftLength];
                     rightInorder[k] = inOrder[k+1+leftLength];
                 }
                 BinaryTreeNode rightRoot =BinaryTree(rightFrontOrder,rightInorder);
                 root.setRight(rightRoot);
                 
              }
          
          
          return root;
      }
          

 面試題七.兩個棧實現一個隊列

先用一個棧存,這樣就是倒序,然后依次取出放入另一個棧,這就是正序了,然后再取出,就和隊列一樣了。

public class sQueue<T> {

    Stack<T> s1 = new Stack<T>();
    Stack<T> s2 = new Stack<T>();
    public void appendTrail(T append){
        s1.push(append);
    }
    
    public T deleteHead(Stack<T> s){
        
        if(s1==null){
            if(s2==null){
                try{
                    throw new Exception("隊列為空");
                }catch(Exception e ){
                     e.printStackTrace(); 
                }
            }    
        }
        while(s1.size()>0){
            s2.push(s1.pop());
        }
         return s2.pop();    
    }
}

 面試題:將企業中員工年齡排序,使用一個長度100的數組作為輔助空間,記錄每個年齡出現的次數,然后按照這個記錄的次數輸出年齡

 public static void sort(int[] ages,int length){
         
         int largeAge = 99;
         int[] timeAge = new int[largeAge+1];
         length = ages.length;
         if(ages==null||length<0){
             return;
         }
         for(int i = 0;i<length;i++){
             int age = ages[i];
             if(ages[i]<0||ages[i]>99){
                 return;
             }
             timeAge[age]++;
         }
         int index = 0;
         for(int j = 0;j<=largeAge;j++){
             for(int k =0;k<timeAge[j];k++){
                 ages[index] = j;
                 index++;
             }
         }
     }
          

 面試題八.求旋轉數組的最小值

  public static int findMin(int[] num){
         if(num==null||num.length<=0){              
             return 0;
         }
         int middle = num.length/2;
         int front = 0;
         int back = num.length-1;
         while(num[front]>num[back]){
             if(back-front==1){
                 middle = back;
                 break;
             }
              middle = (front+back)/2;
              
             if(num[middle]==num[front]&&num[front]==num[back]){              10111 這種情況就需要順序遍歷來找了 return 0;
             }
             
             if(num[middle]>num[front]){
                 front = middle;
                
             }
             if(num[middle]<num[front]){
                 back = middle;
                 
             }
         }
         return num[middle];
 }

 

 面試題九:斐波那契數列

f(n) = f(n-1)+f(n-2)      類似的有上台階問題,一次能邁1個或2個台階,問有多少種方法上樓梯。邁上終點之前肯定是邁了一步或是兩步,那n-1個台階的方法數加上n-2個台階的方法數就是n個台階的方法數。

那么如果一次能邁的台階數沒有限制呢,1,2,3,。。。n       用歸納法得出f(n) = 2的n-1次方

public static int fibonaci(int n){
         if(n==0){
             return 0;
         }else if(n==1){
             return 1;
         }
         else{
             int front = 0;
             int back =1;
             int x =0;
             for(int i =0;i<=n;i++){
                 x = front+back;
                 front = back;
                 back =x;
             }
             return x;
         }
         
     }

 類似的格子填充問題

 面試題十:二進制中1的個數

正數(1,0x7FFFFFFF)負數(0x80000000,0xFFFFFFFF)

解法:十進制中的1二進制表示為00000001,我們可以借助它和要檢驗的二進制數A相與,這樣,就可以根據結果獲知 A中最后一位是0還是1。

1.第一次相與后,把A右移一位,再次相與,這樣依次右移就可以知道每一位是0是1。但是當A為負數時這種方法不可行。移位前是負數的話,就要保證移位后是負數,這樣移位后最高位自動置1.

2.第一次相與后,將00000001依次向左移動一位,這是一種較好的方法,因為不確定A的大小,移動可能會產生影響。

3.最好的解法:比如一個1100,將1100減去1是1011,然后將1100和1011相與得出1000,這樣1100中最右邊的1就變為0。再執行一次的話就變成0000。這樣執行n次后A變為0,那么A中就有n個1.

把一個二進制A和B=(A-1)相與,那么A的最后一個1變0.

public static void main(String[] args){
          int n =10;
          int c = count(n);
          System.out.println(c);
     }       
     public static int count(int n){
         int num = 0;
         while(n!=0){
             n = n&(n-1);
             num++;
         }
         return num;
     }

 

相關題目1:一個數是否為2的整數次方。

解法:一個數如果是2的整數次方,那么它的二進制有且只有一個1.

相關題目2:求從一個二進制變為另一個需要改變多少位。

解法:兩數異或,統計二進制結果中1的數目。

面試題11.數的整數次冪

base為0,指數為負的情況也要考慮到。 指數為負,把指數取正,然后結果取倒數。

 public static void main(String[] args){
          double a = power(2,5);
          System.out.println(a);
     }       
     public static  double power(double base,int exponent){
          
          if(exponent ==0 ){
              return 1;
          }
          if(exponent == 1){
              return base;
          }
          if(exponent>>1==0){
              int exponent1 = exponent>>1;
              double result = power(base,exponent1);
             return result*result;
          }else{
              int exponent2 = exponent-1;
              double result = power(base,exponent2);
             return result*base;
          }
          
     }

 面試題十二:輸出1到n位最大整數

如果按照最簡單的循環輸出,會遇到邊界問題,n非常大的話,int甚至long都不能滿足需求,所以這里需要用數組或者是字符串來表示要輸出的數字。

如果面試題給定了一個n位整數,那么就是大數問題,用字符串來解決。

給定兩個整數相加求結果,也是大數問題。

public static void main(String[] args){
          bigData(3);
     }       
      public static void bigData(int n){
          char[] num = new char[n];
          for(int i = 0;i<n;i++){
              num[i] = '0';
          }
          boolean end = false;
         
          while(!end){
              num[n-1]++;
               for(int k =n-1;k>0;k--){
                   if(num[k]=='9'+1){
                       num[k] = '0';
                       num[k-1]++;
                   }
               }
               if(num[0]=='9'+1){
                   end = true;
                   break;
               }
               boolean out = false; 
            for(int j =0;j<n;j++){
                if(num[j]=='0'&&!out){                        //out是為了避免像100這樣的數字,后邊的兩個0不會輸出,當遇到第一個非0數字后,改變end狀態,就不會進入忽略0的語句。
                    continue;
                }else{
                    out = true;
                    System.out.print(num[j]);
                }
            } 
            System.out.println("...");
          }
}

 面試題十三:在O(1)時間內刪除單向鏈表中的一個節點

思路:如果從首部開始依次查找,那么時間是O(n).

        既然我們知道要刪除的結點i,那么我們就知道它指向的下一個結點j,那么我們可以將j的內容復制到i,然后將i的指針指向j的下一個結點,這樣雖然看起來我們刪除的是j結點,但是實際刪除的是i。

        此外還要考慮的問題是:如果結點不存在怎么辦?如果結點是尾結點怎么辦?鏈表只有一個結點?      

public class deleteInode {

    public static void main(String[] args) {
         ListNode head = new ListNode(0);
         ListNode node1 = new ListNode(1);
         ListNode node2 = new ListNode(2);
         ListNode node3 = new ListNode(3);
         head.setNext(node1);
         node1.setNext(node2);
         node2.setNext(node3);
         delete(head,node2);
         printListNode(head);
         
    }
    public static void delete(ListNode head,ListNode target){
        if(head==null||target==null){
            return;
        }
        if(head.getNext()==null){
            if(head==target){
                head=null;
            }else{
                return;
            }
        }
        if(target.getNext()==null){
            ListNode currentNode = head;
            while(currentNode.getNext()!=null){
                currentNode = currentNode.getNext();
            }
            currentNode.setNext(null);
        }
        if(target.getNext()!=null){
            target.setValue(target.getNext().getValue());
            if(target.getNext().getNext()!=null){
            target.setNext(target.getNext().getNext()); 
            }else{
                target.setNext(null);
            }
        }
    }
    public static void printListNode(ListNode head){
        ListNode current = head;
        while(current!=null){
            System.out.println(current.getValue()+"...");
            current = current.getNext();
        }
    }

}

 

面試題十五.鏈表中倒數第K個結點

思路:兩個指針A、B,最開始都指向第一個結點,先讓A向前走k-1步,然后從第K步開始,A和B同時向前走,這樣,當A到達最后一個結點時,B的位置就是倒數第K個結點。

 public static ListNode findKNode(ListNode head,int k){
         if(head==null){
             return null;                                       //重要!!!魯棒性的判斷
         }
         if(k<1){
             return null; }
          ListNode firstNode = head;
          ListNode secondNode = head;
         
          for(int i =0;i<k-1;i++){
              if(firstNode.getNext()!=null){
              firstNode = firstNode.getNext();
          }else{
              return null;
               }
          }          
          while(firstNode.getNext()!=null){
              firstNode = firstNode.getNext();
              secondNode = secondNode.getNext();
          }
          return secondNode;
          
     }
     

 

相關問題1:求鏈表的中間結點

解決方法:兩個指針,第一個一次走兩步,第二個一次走一步,第一個到達終點時,第二個到達中點。

相關問題2:環形鏈表問題

解決方法:也是兩個指針不一樣的速度走,如果第一個指針到達終點(getNext()等於空)時都沒有碰到第二個,那么就不是環形鏈表。

注:環形鏈表可以是首尾相連(O型),也可以是尾部和中間的某個結點相連(6型)。

 

 面試題十六:反轉鏈表

反轉鏈表相當於喊向后轉的口號之后,隊首變隊尾,隊尾變隊首。

下圖說明了存在的一個隱患,那就是當把(i)結點的指針指向h時,這時如果沒有提前將(j)結點存儲,那么下一步就找不到(j)結點了,鏈表會斷裂。

所以我們要聲明三個變量,分別記錄h、i、j,對應上一個、當前、下一個。

public class Test {

     public static void main(String[] args){
         
         ListNode head = new ListNode(0);
         ListNode node1 = new ListNode(1);
         ListNode node2 = new ListNode(2);
         ListNode node3 = new ListNode(3);
         head.setNext(node1);
         node1.setNext(node2);
         node2.setNext(node3);
         ListNode node = reverseNode(head);
         print(node);
     }
     public static ListNode reverseNode(ListNode head){
         if(head==null){
             return null;
         }
         ListNode preNode = null;
         ListNode curNode = head;
         ListNode nextNode = null;
         ListNode reverseNode = null;
      while(curNode!=null){
           nextNode = curNode.getNext();
           if(nextNode==null){
              reverseNode = curNode;
           }
           curNode.setNext(preNode);
           preNode = curNode;
           curNode = nextNode;
         }
         return reverseNode;
     }
     
     
     public static void print(ListNode head){
         ListNode current = head;
         while(current!=null){
            System.out.println(current.getValue());
            current = current.getNext();
         }
     }
} 

 面試題十七:合並兩個已排序的鏈表

其實這是一個遞歸問題,在比較兩個鏈表的頭結點后,選定其中一個做為新鏈表的結點,那么產生下一個結點的過程和最開始一樣,兩個鏈表的頭結點中選擇一個做為新鏈表的下一個結點,所以是遞歸問題。

public class Test {

     public static void main(String[] args){
         
         ListNode head1 = new ListNode(1);
         ListNode node1 = new ListNode(3);
         ListNode node2 = new ListNode(5);
         ListNode node3 = new ListNode(7);
         head1.setNext(node1);
         node1.setNext(node2);
         node2.setNext(node3);
         ListNode head2 = new ListNode(2);
         ListNode node4 = new ListNode(4);
         ListNode node5 = new ListNode(6);
         ListNode node6 = new ListNode(8);
         head2.setNext(node4);
         node4.setNext(node5);
         node5.setNext(node6);
         ListNode head = merge(head1,head2);
         print(head);
     }
      public static ListNode merge(ListNode headA,ListNode headB){
          ListNode nodeA = headA;
          ListNode nodeB = headB;
          ListNode head = null;
          if(headA==null&&headB!=null){
              head = headB;
          }
          if(headB==null&&headA!=null){
              head = headA;
          }
          if(headA==null&&headB==null){
              return null;
          }
          if(nodeA!=null&&nodeB!=null){
              if(nodeA.getValue()<nodeB.getValue()){
                  head = nodeA;
                 head.setNext(merge(nodeA.getNext(),nodeB));
              }else{
                 head = nodeB;
                 head.setNext(merge(nodeA,nodeB.getNext()));
                 }
          }
          return head;
      }   
      public static void print(ListNode head){
          ListNode curNode = head;
          while(curNode!=null){
              System.out.println(curNode.getValue());
              curNode = curNode.getNext();
          }
      }
     
     
  
} 

 面試題十八:樹的子結構

兩個遞歸方法,一個是尋找相同的結點,如果遇到相同結點,就調用比較左右子結點的方法。如果根節點和目標結點不相同,就比較左右子結點和目標是否相同,相同,就調用比較子結點方法,不相同,繼續調用尋找相同結點方法。

public class Test {

     public static void main(String[] args){
         BinaryTreeNode root = new BinaryTreeNode(8);
         BinaryTreeNode node1 = new BinaryTreeNode(8);
         BinaryTreeNode node2 = new BinaryTreeNode(7);
         BinaryTreeNode node3 = new BinaryTreeNode(9);
         BinaryTreeNode node4 = new BinaryTreeNode(2);
         root.setLeft(node1);
         root.setRight(node2);
         node1.setLeft(node3);
         node1.setRight(node4);
         BinaryTreeNode target = new BinaryTreeNode(8);
         BinaryTreeNode node5 = new BinaryTreeNode(9);
         BinaryTreeNode node6 = new BinaryTreeNode(2);
         target.setLeft(node5);
         target.setRight(node6);
         
         boolean result2 = findSame(root,target);
         System.out.println(result2);
         
         
     }
     public static boolean findSame(BinaryTreeNode root,BinaryTreeNode target){
         boolean result = false;
         if(root!=null&&target!=null){
                 if(root.getValue()==target.getValue()){
                    result = sameTree(root,target);
                 }
                 if(!result){
                    result = findSame(root.getLeft(),target);
                 }
                 if(!result){
                    result = findSame(root.getRight(),target);
                    }
            }
     
         return result;
     }
     public static boolean sameTree(BinaryTreeNode node,BinaryTreeNode target){
         if(target==null){
             return true;
         }
         if(node ==null ){
             return false;
         }
         
         if(node.getValue()!=target.getValue()){
             return false;
         }
         return sameTree(node.getLeft(),target.getLeft())&&sameTree(node.getRight(),node.getRight());
     }
     
} 

 面試題十九:二叉樹鏡像

貌似對於二叉樹的整體操作都是遞歸問題,因為操作過根節點之后,左右兩顆子樹就可以看成單獨的樹遞歸操作。

打印二叉樹的時候,每次打印根結點就可以,因為每個結點輸出之后,它的子結點都可以看作根結點。

public class Test {

     public static void main(String[] args){
         BinaryTreeNode root = new BinaryTreeNode(8);
         BinaryTreeNode node1 = new BinaryTreeNode(8);
         BinaryTreeNode node3 = new BinaryTreeNode(9);
         BinaryTreeNode node2 = new BinaryTreeNode(7);
         BinaryTreeNode node4 = new BinaryTreeNode(6);
         root.setLeft(node1);
         root.setRight(node3);
         node1.setLeft(node2);
         node3.setRight(node4);
         mirrorBinary(root);
         printBinaryTree(root);
     }
     public static void mirrorBinary(BinaryTreeNode root){
         if(root == null){
             return;
         }
         if(root.getLeft()==null&&root.getRight()==null){
             return;
         }
         BinaryTreeNode temp = root.getLeft();
         root.setLeft(root.getRight());
         root.setRight(temp);
         if(root.getLeft()!=null){
         mirrorBinary(root.getLeft());
         }
         if(root.getRight()!=null){
         mirrorBinary(root.getRight());
         }
     }
     public static void printBinaryTree(BinaryTreeNode root){
        if(root!=null){
         System.out.println(root.getValue());
        printBinaryTree(root.getLeft());
        printBinaryTree(root.getRight());
     }
     }
}

按照循環的方法做,就要用到隊列了, 利用隊列的先進先出的性質,依次添加所有結點,在取出每個結點時,並不對結點操作,而是對結點的兩個子結點進行添加進隊列和交換的操作。

 這里利用隊列的方法類似於二叉樹的分層遍歷所采用的方法。

 public static void mirrorBinary(BinaryTreeNode root){
         Queue<BinaryTreeNode> q = new LinkedList<BinaryTreeNode>();
         BinaryTreeNode temp = new BinaryTreeNode(0);
         if(root!=null){
            q.add(root);
         }
         while(q.size()>0){
             BinaryTreeNode node = q.poll();
             if(node.getLeft()!=null){
                 q.add(node.getLeft());
             }
             if(node.getRight()!=null){
                 q.add(node.getRight());
             }
             temp = node.getLeft();
             node.setLeft(node.getRight());
             node.setRight(temp);
         }
     }

 

面試題二十:順時針打印矩陣(按圈打印)

public class Test {

     public static void main(String[] args){
         BinaryTreeNode root = new BinaryTreeNode(8);
         int[][] num = {{1,2,3,4},{5,6,7,8,},{1,3,5,7,},{2,4,6,8}};
         print(num,4,4);
     }
     public static void print(int[][] num,int rows,int columns){
         if(num==null||rows<=0||columns<=0){
             return;
         }
         int temp = 0;
         while(rows>temp*2&&columns>temp*2){
             printCircle(num,temp,rows,columns);
             temp++;
         }
     }
    private static void printCircle(int[][] num,int start,int rows,int columns) {
        int endRow = rows-1-start;
        int endColumn = columns-1-start;
        for(int i = start;i<=endColumn;i++){
            System.out.print(num[start][i]);
        }
        //如果行數大於起始值,那么肯定不止一行,所以最右一列可以打印
        if(start<endRow){
            for(int i = start+1;i<=endRow;i++){
                System.out.print(num[i][endRow]);
            }
        }
        //從右到左打印最下一行
        if(start<endRow&&start<endColumn){
            for(int i = endColumn-1;i>=start;i--){
                System.out.print(num[endRow][i]);
            }
        }
        //打印最左邊一列
        if(start<endColumn&&start<endRow-1){
            for(int i =endRow-1;i>start;i--){
                System.out.print(num[i][start]);
            }
        }
        System.out.println(".......");
    }
} 

 面試題二十一:包含min函數的棧

創建一個輔助棧,在每次存入新元素時,將新元素和輔助棧的棧頂元素相比,如果棧頂元素小,則再添加一次棧頂元素,否則添加新元素。這樣可以保證輔助棧的棧頂始終都是原本棧中的最小元素。

public class minStack {

    private Stack<Integer> stack1;
    private Stack<Integer> stackHelp;
    private  int temp,pop1,pop2;
    public minStack(){
        stack1 = new Stack<Integer>();
        stackHelp = new Stack<Integer>();
    }
    public  void push(int num){     
        stack1.push(num);
        if(stackHelp.size()==0||num<stackHelp.peek()){
            stackHelp.push(num);
        }else{
            stackHelp.push(stackHelp.peek());
        }
    }
    public void pop(){
        pop1 = stack1.pop();
        pop2 = stackHelp.pop();
        System.out.println("本棧是"+pop1+"輔助棧是"+pop2);
    }
    public void min(){
        System.out.println("最小值是"+stackHelp.pop());
    } 
}

 

面試題二十二:棧的壓入,彈出序列

輸入兩組數,判斷一個是否是另一個的彈棧順序。比如A{1,2,3,4,5} B{1,2,5,3,4}  在依次往A中壓入元素時,不斷比較棧頂元素,1,2,3,當A棧中4進入時,等於B中棧頂元素,那么4彈出。再比較A和B的棧頂元素,都是3,3出棧。然后A是2,B是5,不相同,則5進入A棧,此時棧頂元素相同,5出棧。然后就是2,1.   則第二個數組滿足條件。

public class Test {

     public static void main(String[] args){
           int[] numPush = {1,2,3,4,5};
           int[] numPop = {4,3,5,2,1};
           System.out.println(isPopOrder(numPush,numPop));
     }
     public static boolean isPopOrder(int[] numPush,int[] numPop ){
         if(numPush.length<=0||numPop.length<=0||numPush.length!=numPop.length){
             return false;
         } Stack
<Integer> stackPop = new Stack<Integer>(); for(int i=numPop.length-1;i>=0;i--){ stackPop.push(numPop[i]); } Stack<Integer> stackPush = new Stack<Integer>(); int j = 0; while(j<numPush.length){ if(numPush[j]!=stackPop.peek()){ stackPush.push(numPush[j]); j++; }else{ stackPush.push(numPush[j]); System.out.println(numPush[j]); while(stackPush.size()>0&&stackPop.size()>0&&stackPush.peek()==stackPop.peek()){ System.out.println("..."+stackPush.pop()); System.out.println(".."+stackPop.pop()); } j++; } } if(stackPush.size()==0){ return true; }else{ return false; } } }

 面試題二十四:判斷一個數組是否是某二叉樹的后序遍歷順序

后續遍歷結果最后一個是根節點,除去根節點,數組的前半部分應該都比根節點的值小,數組的后半部分應該都比根節點的值大,按照這個規律,遞歸判斷。

int[] left = Arrays.copyOfRange(num, 0, i);          從第0位截取到i-1位。

 public static boolean isBinaryTree(int[] num ){
         if(num.length<=0){
             return false;
         } 
         int root = num[num.length-1];
         int i = 0 ;
         for(;i<num.length-1;i++){
             if(num[i]>root){
                 break;
             }
         }
         
         
         for(int j =i;j<num.length-1;j++){
             if(num[j]<root){
                 return false;
             }
         }
         int[] left = Arrays.copyOfRange(num, 0, i);
         int[] right = Arrays.copyOfRange(num, i, num.length-1);
         
         Boolean isLeft = true;
         if(left.length>0){
         isBinaryTree(left);
         }
         Boolean isRight = true;
         if(right.length>0){
         isBinaryTree(right);
         }
         return(isLeft&&isRight);
          
     }

 面試題二十五:二叉樹中和為某一值的路徑

     public static void main(String[] args){
         BinaryTreeNode root = new BinaryTreeNode(5);
         BinaryTreeNode node1 = new BinaryTreeNode(4);
         BinaryTreeNode node2 = new BinaryTreeNode(3);
         BinaryTreeNode node3 = new BinaryTreeNode(5);
         BinaryTreeNode node4 = new BinaryTreeNode(1);
         BinaryTreeNode node5 = new BinaryTreeNode(2);
         BinaryTreeNode node6 = new BinaryTreeNode(1);
         root.setLeft(node1);
         root.setRight(node3);
         node1.setLeft(node2);
         node3.setLeft(node4);
         node3.setRight(node5);
         node4.setLeft(node6);
         Stack<Integer> stack = new Stack<Integer>();
         isPath(12,0,root,stack);
          
     }
     public static void isPath(int expectSum,int currentSum,BinaryTreeNode root,Stack<Integer> stack){
         if(root==null){
             return;
         }
         stack.push(root.getValue());
         currentSum += root.getValue();
         if(root.getLeft()==null&&root.getRight()==null&&currentSum==expectSum){
             for(Integer e : stack){ //這種方式輸出不用談棧,元素還在棧里
                 System.out.print(e+"\t");
             }
             System.out.println();
         }
         if(root.getLeft()!=null){
             isPath(expectSum,currentSum,root.getLeft(),stack);
         }
         if(root.getRight()!=null){
             isPath(expectSum,currentSum,root.getRight(),stack);
         }
         stack.pop();     //執行到葉結點(倒數第二層的左子結點)之后,pop,就會回到上一層,然后判斷一下有沒有右子結點,執行下一步沒有的話,再pop,又往上一層,再檢查右子結點。
     
     }

 面試題二十六:復制一個復雜鏈表

復雜鏈表:一個結點可以有兩個指向,一個是next,一個是亂序

1.首先只復制next鏈表,把復制結點放到原本結點的后邊。

2.復制亂序指向

3.分離兩個鏈表,奇數位的連在一起,偶數位的連在一起,就是兩個相同的鏈表。

分離時,使用兩個指針,一個pNode,一個pCloneNode,將pNode的next指向pClonedNode的next之后,移動pNode到第三個,然后將pCloneNode指向pNode的next,然后移動pCloneNode到第四個,這樣不斷移動,實現分離。

 

面試題二十七:二叉搜索樹轉換成有序雙向鏈表

中序遍歷二叉樹得到的結果是有序的。

1,curNode記錄的是上一個結點,當root行進到最左邊葉結點的左子結點時,root為空,程序不執行,退回上一步。上一步的root輸入是最左邊的葉結點。

2,這時從第5行執行,但這時的curNode為空。第9行:curNode = 最左葉結點。第十行:遞歸最左子結點的右子結點,如果存在,那么驗證是否有左子結點,沒有,返回上一層執行第5行,和curNode互指。

3,處理完curNode的子結點,就要返回上一層,這時的root輸入為curNode的父結點,執行第5行互指。然后curNode被設置成root。再去尋找root的右子結點。

過程中,由於程序的對於二叉樹中結點的遍歷順序是左中右,所以curNode的指向也是這個順序。在每一次退出上一層時,curNode的指向都會更新。

程序最開始位於左中右的中,然后尋找右,這里的中和右其實都是上一層的左。返回上一層的中,尋找上一層的右。

1 private BinaryTreeNode curNode ;
2    public  void toTwo(BinaryTreeNode root){
3         if(root!=null){
4          toTwo(root.getLeft());
5         if(curNode!=null){
6            curNode.setLeft(root); 
7            root.setRight(curNode);
8         }
9          curNode = root;
10          toTwo(root.getRight());         
       }
     }

 面試題二十八:字符串的排列

和八皇后問題一樣,都是用 回溯法解決問題。

public class Test {

     private final int SET = 1;
     private final int UNSET = 0;
     private int size;
     private int[] set;
     private char[] c;
     private char[] location;
     private int count;
     public Test(int size,char[] c){
         this.size = size;
         this.c = c;
         location = new char[size];
         set = new int[size];
     }
     public void charSet(int i,int j,int k){
         location[i] = c[j];
         if(k==0){
             set[j] = UNSET;
         }
     }
     public int isPlace(int j){
         return set[j];
     }
     public void print(){
         System.out.println("第"+count+"種方法");
         for(int j=0;j<size;j++){
             System.out.print(location[j]+"."); 
         }
         System.out.println();
     }
     public void  place(int i){
         for(int j = 0;j<size;j++){
             if(set[j]==UNSET){
                 charSet(i,j,1);
                 set[j] = SET;
                 if(i<size-1){
                     place(i+1);
                 }else{
                     count++;
                     print();
                 }
                 charSet(i,j,0);
             }
         }
     } 
     public static void main(String[] args){
         char[] c = {'a'};
         if(c==null){
             return;
         }
         else{
         Test t = new Test(c.length,c);
         t.place(0); 
         }
     }
     
} 

 擴展:求字符的所有組合Input:abc  Output:a,b,c,ab,bc,ac,abc

public class Test {
     public static void main(String[] args){
         perm("abc");
         
     }
     public static void perm(String s){
         List<String> result = new ArrayList<String>();
         for(int i =1;i<=s.length();i++){
             perm(s,i,result);
         }
     }
     public static void perm(String s,int m,List<String> result){
         if(s.length()<m){
             return;
         }
         if(m==0){
             for(int i =0;i<result.size();i++){
                 System.out.println(result.get(i));
             }
             System.out.println();
             return;
         }else{
             if(s.length()!=0){
                 result.add(s.charAt(0)+"");
                 perm(s.substring(1,s.length()),m-1,result);
                 result.remove(result.size()-1);
                 perm(s.substring(1,s.length()),m,result);
             }
         }
     }
     
} 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM