• 剑指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+"	");
                 }
                 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);
                 }
             }
         }
         
    } 
  • 相关阅读:
    Tomcat通过脚本自动部署
    【转】调用百度API,HTML在线文字转语音播报
    vim 多行注释消除注释,多行删除
    sublime快捷键
    引号-下划线,连接多个变量
    图片压缩工具optipng/jpegoptim安装
    netsh-winsock-reset;ping的通公网IP和DNS地址和内网网关,就是不能解析域名;
    mysql简单性能排查
    nginx-upstream-keepalive;accept_mutex-proxy_http_version-1.1-proxy_set_header-connection
    icmp,tcp,traceroute,ping,iptables
  • 原文地址:https://www.cnblogs.com/hugofly/p/4445437.html
Copyright © 2020-2023  润新知