面试题三:查找二维数组中元素问题

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

面试题四:替换字符串中的空格

延伸:1.合并两个字符串     2.两个有序数组,将一个插入到另一个,并保证有序。    从后面开始会减少元素移动的次数?

  1. public static void main(String[] args){
  2. int[][] num = {{1,2,8,9},{2,4,9,12},{4,7,10,13},{6,8,11,15}};
  3. String str = "we are happy";
  4. replaceBlank(str);
  5.  
  6. }
  7. public static void replaceBlank(String str){
  8.  
  9. char[] charOld = str.toCharArray();
  10. char[] charNew = new char[100];
  11. for(int j = 0;j<charOld.length;j++){
  12. charNew[j] = charOld[j];
  13. }
  14. int blank = 0;
  15. for(int i = 0;i<charNew.length;i++){
  16. if(charNew[i]==' '){
  17. blank++;
  18. }
  19. }
  20. int lengthFront = charOld.length-1;
  21.  
  22. int lengthBack = charOld.length+2*blank-1;
  23.  
  24. while(lengthFront>=0&&lengthBack>=0){
  25. if(charNew[lengthFront]!=' '){
  26. charNew[lengthBack--] = charNew[lengthFront];
  27. }
  28. else
  29. {
  30. charNew[lengthBack--] = '0';
  31. charNew[lengthBack--] = '2';
  32. charNew[lengthBack--] = '%';
  33. lengthFront--;
  34. }
  35. lengthFront--;
  36. }
  37. System.out.println(charNew);
  38.  
  39. }

面试题5.从尾到头打印链表(利用栈或递归来实现)

构建链表

  1. public class ListNode {
  2. private int value;
  3. private ListNode next;
  4. public ListNode(int value){
  5. this.value = value;
  6. }
  7.  
  8. public ListNode(int value,ListNode next){
  9. this.value = value;
  10. this.next = next;
  11. }
  12.  
  13. public void setValue(int value){
  14. this.value = value;
  15. }
  16.  
  17. public int getValue(ListNode node){
  18. return node.value;
  19. }
  20. public void setNext(ListNode next){
  21. this.next = next;
  22. }
  23. public ListNode getNext(){
  24. return this.next;
  25. }
  26.  
  27. }

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());                                             }

}

面试题六:根据前序和中序输出构造二叉树

建二叉树

  1. public class BinaryTreeNode {
  2.  
  3. private int value;
  4. private BinaryTreeNode left;
  5. private BinaryTreeNode right;
  6. public BinaryTreeNode(int value){
  7. this.value = value;
  8. }
  9. public BinaryTreeNode(int value,BinaryTreeNode left,BinaryTreeNode right){
  10. this.value = value;
  11. this.left = left;
  12. this.right = right;
  13. }
  14. public int getValue( ){
  15. return this.value;
  16. }
  17. public void setValue(BinaryTreeNode node){
  18. this.value = value;
  19. }
  20. public void setLeft(BinaryTreeNode node){
  21. this.left = node;
  22. }
  23. public void setRight(BinaryTreeNode node){
  24. this.right = node;
  25. }
  26. public BinaryTreeNode getLeft( ){
  27. return this.left;
  28. }
  29. public BinaryTreeNode getRight( ){
  30. return this.right;
  31. }
  32. }

根据前序找根节点,然后判断根节点在中序输出中的位置,根节点左边的就是左子树,右边的就是右子树,然后递归调用此方法。

  1. public static void main(String[] args){
  2. int[][] num = {{1,2,8,9},{2,4,9,12},{4,7,10,13},{6,8,11,15}};
  3. int[] frontOrder = {1,2,4,7,3,5,6,8};
  4. int[] inOrder = {4,7,2,1,5,3,8,6};
  5. BinaryTreeNode root =BinaryTree(frontOrder,inOrder);
  6. printPostOrder(root);
  7.  
  8. }
  9. public static void printPostOrder(BinaryTreeNode root){
  10. if(root!=null){
  11. printPostOrder(root.getLeft( ));
  12. printPostOrder(root.getRight( ));
  13. System.out.println(root.getValue());
  14. }
  15. }
  16. public static BinaryTreeNode BinaryTree(int[] frontOrder,int[] inOrder){
  17. BinaryTreeNode root = new BinaryTreeNode(frontOrder[0]);
  18. root.setLeft(null);
  19. root.setRight(null);
  20.  
  21. int leftLength = 0;
  22. for(int i =0;i<inOrder.length;i++){
  23. if(inOrder[i]==root.getValue( )){
  24. break;
  25. }else{
  26. leftLength++;
  27. }
  28. }
  29. int rightLength = inOrder.length-leftLength-1;
  30.  
  31. if(leftLength>0){
  32. int[] leftFrontOrder = new int[leftLength];
  33. int[] leftInorder = new int[leftLength];
  34. for(int j = 0;j<leftLength;j++){
  35. leftFrontOrder[j] = frontOrder[j+1];
  36. leftInorder[j] = inOrder[j];
  37. }
  38. BinaryTreeNode leftRoot = BinaryTree(leftFrontOrder,leftInorder);
  39. root.setLeft(leftRoot);
  40. }
  41. if(rightLength>0){
  42. int[] rightFrontOrder = new int[rightLength];
  43. int[] rightInorder = new int[rightLength];
  44. for(int k = 0;k<rightLength;k++){
  45. rightFrontOrder[k] = frontOrder[k+1+leftLength];
  46. rightInorder[k] = inOrder[k+1+leftLength];
  47. }
  48. BinaryTreeNode rightRoot =BinaryTree(rightFrontOrder,rightInorder);
  49. root.setRight(rightRoot);
  50.  
  51. }
  52.  
  53. return root;
  54. }

面试题七.两个栈实现一个队列

先用一个栈存,这样就是倒序,然后依次取出放入另一个栈,这就是正序了,然后再取出,就和队列一样了。

  1. public class sQueue<T> {
  2.  
  3. Stack<T> s1 = new Stack<T>();
  4. Stack<T> s2 = new Stack<T>();
  5. public void appendTrail(T append){
  6. s1.push(append);
  7. }
  8.  
  9. public T deleteHead(Stack<T> s){
  10.  
  11. if(s1==null){
  12. if(s2==null){
  13. try{
  14. throw new Exception("队列为空");
  15. }catch(Exception e ){
  16. e.printStackTrace();
  17. }
  18. }
  19. }
  20. while(s1.size()>0){
  21. s2.push(s1.pop());
  22. }
  23. return s2.pop();
  24. }
  25. }

面试题:将企业中员工年龄排序,使用一个长度100的数组作为辅助空间,记录每个年龄出现的次数,然后按照这个记录的次数输出年龄

  1. public static void sort(int[] ages,int length){
  2.  
  3. int largeAge = 99;
  4. int[] timeAge = new int[largeAge+1];
  5. length = ages.length;
  6. if(ages==null||length<0){
  7. return;
  8. }
  9. for(int i = 0;i<length;i++){
  10. int age = ages[i];
  11. if(ages[i]<0||ages[i]>99){
  12. return;
  13. }
  14. timeAge[age]++;
  15. }
  16. int index = 0;
  17. for(int j = 0;j<=largeAge;j++){
  18. for(int k =0;k<timeAge[j];k++){
  19. ages[index] = j;
  20. index++;
  21. }
  22. }
  23. }

面试题八.求旋转数组的最小值

  1. public static int findMin(int[] num){
  2. if(num==null||num.length<=0){
  3. return 0;
  4. }
  5. int middle = num.length/2;
  6. int front = 0;
  7. int back = num.length-1;
  8. while(num[front]>num[back]){
  9. if(back-front==1){
  10. middle = back;
  11. break;
  12. }
  13. middle = (front+back)/2;
  14.  
  15. if(num[middle]==num[front]&&num[front]==num[back]){ 10111 这种情况就需要顺序遍历来找了
  16. return 0;
  17. }
  18.  
  19. if(num[middle]>num[front]){
  20. front = middle;
  21.  
  22. }
  23. if(num[middle]<num[front]){
  24. back = middle;
  25.  
  26. }
  27. }
  28. return num[middle];
  29. }

面试题九:斐波那契数列

f(n) = f(n-1)+f(n-2)      类似的有上台阶问题,一次能迈1个或2个台阶,问有多少种方法上楼梯。迈上终点之前肯定是迈了一步或是两步,那n-1个台阶的方法数加上n-2个台阶的方法数就是n个台阶的方法数。

那么如果一次能迈的台阶数没有限制呢,1,2,3,。。。n       用归纳法得出f(n) = 2的n-1次方

  1. public static int fibonaci(int n){
  2. if(n==0){
  3. return 0;
  4. }else if(n==1){
  5. return 1;
  6. }
  7. else{
  8. int front = 0;
  9. int back =1;
  10. int x =0;
  11. for(int i =0;i<=n;i++){
  12. x = front+back;
  13. front = back;
  14. back =x;
  15. }
  16. return x;
  17. }
  18.  
  19. }

类似的格子填充问题

面试题十:二进制中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.

  1. public static void main(String[] args){
  2. int n =10;
  3. int c = count(n);
  4. System.out.println(c);
  5. }
  6. public static int count(int n){
  7. int num = 0;
  8. while(n!=0){
  9. n = n&(n-1);
  10. num++;
  11. }
  12. return num;
  13. }

相关题目1:一个数是否为2的整数次方。

解法:一个数如果是2的整数次方,那么它的二进制有且只有一个1.

相关题目2:求从一个二进制变为另一个需要改变多少位。

解法:两数异或,统计二进制结果中1的数目。

面试题11.数的整数次幂

base为0,指数为负的情况也要考虑到。 指数为负,把指数取正,然后结果取倒数。

  1.  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位整数,那么就是大数问题,用字符串来解决。

给定两个整数相加求结果,也是大数问题。

  1. public static void main(String[] args){
  2. bigData(3);
  3. }
  4. public static void bigData(int n){
  5. char[] num = new char[n];
  6. for(int i = 0;i<n;i++){
  7. num[i] = '0';
  8. }
  9. boolean end = false;
  10.  
  11. while(!end){
  12. num[n-1]++;
  13. for(int k =n-1;k>0;k--){
  14. if(num[k]=='9'+1){
  15. num[k] = '0';
  16. num[k-1]++;
  17. }
  18. }
  19. if(num[0]=='9'+1){
  20. end = true;
  21. break;
  22. }
  23. boolean out = false;
  24. for(int j =0;j<n;j++){
  25. if(num[j]=='0'&&!out){ //out是为了避免像100这样的数字,后边的两个0不会输出,当遇到第一个非0数字后,改变end状态,就不会进入忽略0的语句。
  26. continue;
  27. }else{
  28. out = true;
  29. System.out.print(num[j]);
  30. }
  31. }
  32. System.out.println("...");
  33. }
    }

面试题十三:在O(1)时间内删除单向链表中的一个节点

思路:如果从首部开始依次查找,那么时间是O(n).

既然我们知道要删除的结点i,那么我们就知道它指向的下一个结点j,那么我们可以将j的内容复制到i,然后将i的指针指向j的下一个结点,这样虽然看起来我们删除的是j结点,但是实际删除的是i。

此外还要考虑的问题是:如果结点不存在怎么办?如果结点是尾结点怎么办?链表只有一个结点?

  1. public class deleteInode {
  2.  
  3. public static void main(String[] args) {
  4. ListNode head = new ListNode(0);
  5. ListNode node1 = new ListNode(1);
  6. ListNode node2 = new ListNode(2);
  7. ListNode node3 = new ListNode(3);
  8. head.setNext(node1);
  9. node1.setNext(node2);
  10. node2.setNext(node3);
  11. delete(head,node2);
  12. printListNode(head);
  13.  
  14. }
  15. public static void delete(ListNode head,ListNode target){
  16. if(head==null||target==null){
  17. return;
  18. }
  19. if(head.getNext()==null){
  20. if(head==target){
  21. head=null;
  22. }else{
  23. return;
  24. }
  25. }
  26. if(target.getNext()==null){
  27. ListNode currentNode = head;
  28. while(currentNode.getNext()!=null){
  29. currentNode = currentNode.getNext();
  30. }
  31. currentNode.setNext(null);
  32. }
  33. if(target.getNext()!=null){
  34. target.setValue(target.getNext().getValue());
  35. if(target.getNext().getNext()!=null){
  36. target.setNext(target.getNext().getNext());
  37. }else{
  38. target.setNext(null);
  39. }
  40. }
  41. }
  42. public static void printListNode(ListNode head){
  43. ListNode current = head;
  44. while(current!=null){
  45. System.out.println(current.getValue()+"...");
  46. current = current.getNext();
  47. }
  48. }
  49.  
  50. }

面试题十五.链表中倒数第K个结点

思路:两个指针A、B,最开始都指向第一个结点,先让A向前走k-1步,然后从第K步开始,A和B同时向前走,这样,当A到达最后一个结点时,B的位置就是倒数第K个结点。

  1. public static ListNode findKNode(ListNode head,int k){
  2. if(head==null){
  3. return null; //重要!!!鲁棒性的判断
  4. }
  5. if(k<1){
  6. return null;
  7. }
  8. ListNode firstNode = head;
  9. ListNode secondNode = head;
  10.  
  11. for(int i =0;i<k-1;i++){
  12. if(firstNode.getNext()!=null){
  13. firstNode = firstNode.getNext();
  14. }else{
  15. return null;
  16. }
  17. }
  18. while(firstNode.getNext()!=null){
  19. firstNode = firstNode.getNext();
  20. secondNode = secondNode.getNext();
  21. }
  22. return secondNode;
  23.  
  24. }

相关问题1:求链表的中间结点

解决方法:两个指针,第一个一次走两步,第二个一次走一步,第一个到达终点时,第二个到达中点。

相关问题2:环形链表问题

解决方法:也是两个指针不一样的速度走,如果第一个指针到达终点(getNext()等于空)时都没有碰到第二个,那么就不是环形链表。

注:环形链表可以是首尾相连(O型),也可以是尾部和中间的某个结点相连(6型)。

面试题十六:反转链表

反转链表相当于喊向后转的口号之后,队首变队尾,队尾变队首。

下图说明了存在的一个隐患,那就是当把(i)结点的指针指向h时,这时如果没有提前将(j)结点存储,那么下一步就找不到(j)结点了,链表会断裂。

所以我们要声明三个变量,分别记录h、i、j,对应上一个、当前、下一个。

  1. public class Test {
  2.  
  3. public static void main(String[] args){
  4.  
  5. ListNode head = new ListNode(0);
  6. ListNode node1 = new ListNode(1);
  7. ListNode node2 = new ListNode(2);
  8. ListNode node3 = new ListNode(3);
  9. head.setNext(node1);
  10. node1.setNext(node2);
  11. node2.setNext(node3);
  12. ListNode node = reverseNode(head);
  13. print(node);
  14. }
  15. public static ListNode reverseNode(ListNode head){
  16. if(head==null){
  17. return null;
  18. }
  19. ListNode preNode = null;
  20. ListNode curNode = head;
  21. ListNode nextNode = null;
  22. ListNode reverseNode = null;
  23. while(curNode!=null){
  24. nextNode = curNode.getNext();
  25. if(nextNode==null){
  26. reverseNode = curNode;
  27. }
  28. curNode.setNext(preNode);
  29. preNode = curNode;
  30. curNode = nextNode;
  31. }
  32. return reverseNode;
  33. }
  34.  
  35. public static void print(ListNode head){
  36. ListNode current = head;
  37. while(current!=null){
  38. System.out.println(current.getValue());
  39. current = current.getNext();
  40. }
  41. }
  42. }

面试题十七:合并两个已排序的链表

其实这是一个递归问题,在比较两个链表的头结点后,选定其中一个做为新链表的结点,那么产生下一个结点的过程和最开始一样,两个链表的头结点中选择一个做为新链表的下一个结点,所以是递归问题。

  1. public class Test {
  2.  
  3. public static void main(String[] args){
  4.  
  5. ListNode head1 = new ListNode(1);
  6. ListNode node1 = new ListNode(3);
  7. ListNode node2 = new ListNode(5);
  8. ListNode node3 = new ListNode(7);
  9. head1.setNext(node1);
  10. node1.setNext(node2);
  11. node2.setNext(node3);
  12. ListNode head2 = new ListNode(2);
  13. ListNode node4 = new ListNode(4);
  14. ListNode node5 = new ListNode(6);
  15. ListNode node6 = new ListNode(8);
  16. head2.setNext(node4);
  17. node4.setNext(node5);
  18. node5.setNext(node6);
  19. ListNode head = merge(head1,head2);
  20. print(head);
  21. }
  22. public static ListNode merge(ListNode headA,ListNode headB){
  23. ListNode nodeA = headA;
  24. ListNode nodeB = headB;
  25. ListNode head = null;
  26. if(headA==null&&headB!=null){
  27. head = headB;
  28. }
  29. if(headB==null&&headA!=null){
  30. head = headA;
  31. }
  32. if(headA==null&&headB==null){
  33. return null;
  34. }
  35. if(nodeA!=null&&nodeB!=null){
  36. if(nodeA.getValue()<nodeB.getValue()){
  37. head = nodeA;
  38. head.setNext(merge(nodeA.getNext(),nodeB));
  39. }else{
  40. head = nodeB;
  41. head.setNext(merge(nodeA,nodeB.getNext()));
  42. }
  43. }
  44. return head;
  45. }
  46. public static void print(ListNode head){
  47. ListNode curNode = head;
  48. while(curNode!=null){
  49. System.out.println(curNode.getValue());
  50. curNode = curNode.getNext();
  51. }
  52. }
  53.  
  54. }

面试题十八:树的子结构

两个递归方法,一个是寻找相同的结点,如果遇到相同结点,就调用比较左右子结点的方法。如果根节点和目标结点不相同,就比较左右子结点和目标是否相同,相同,就调用比较子结点方法,不相同,继续调用寻找相同结点方法。

  1. public class Test {
  2.  
  3. public static void main(String[] args){
  4. BinaryTreeNode root = new BinaryTreeNode(8);
  5. BinaryTreeNode node1 = new BinaryTreeNode(8);
  6. BinaryTreeNode node2 = new BinaryTreeNode(7);
  7. BinaryTreeNode node3 = new BinaryTreeNode(9);
  8. BinaryTreeNode node4 = new BinaryTreeNode(2);
  9. root.setLeft(node1);
  10. root.setRight(node2);
  11. node1.setLeft(node3);
  12. node1.setRight(node4);
  13. BinaryTreeNode target = new BinaryTreeNode(8);
  14. BinaryTreeNode node5 = new BinaryTreeNode(9);
  15. BinaryTreeNode node6 = new BinaryTreeNode(2);
  16. target.setLeft(node5);
  17. target.setRight(node6);
  18.  
  19. boolean result2 = findSame(root,target);
  20. System.out.println(result2);
  21.  
  22. }
  23. public static boolean findSame(BinaryTreeNode root,BinaryTreeNode target){
  24. boolean result = false;
  25. if(root!=null&&target!=null){
  26. if(root.getValue()==target.getValue()){
  27. result = sameTree(root,target);
  28. }
  29. if(!result){
  30. result = findSame(root.getLeft(),target);
  31. }
  32. if(!result){
  33. result = findSame(root.getRight(),target);
  34. }
  35. }
  36.  
  37. return result;
  38. }
  39. public static boolean sameTree(BinaryTreeNode node,BinaryTreeNode target){
  40. if(target==null){
  41. return true;
  42. }
  43. if(node ==null ){
  44. return false;
  45. }
  46.  
  47. if(node.getValue()!=target.getValue()){
  48. return false;
  49. }
  50. return sameTree(node.getLeft(),target.getLeft())&&sameTree(node.getRight(),node.getRight());
  51. }
  52.  
  53. }

面试题十九:二叉树镜像

貌似对于二叉树的整体操作都是递归问题,因为操作过根节点之后,左右两颗子树就可以看成单独的树递归操作。

打印二叉树的时候,每次打印根结点就可以,因为每个结点输出之后,它的子结点都可以看作根结点。

  1. public class Test {
  2.  
  3.      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());
         }
         }
    }

按照循环的方法做,就要用到队列了, 利用队列的先进先出的性质,依次添加所有结点,在取出每个结点时,并不对结点操作,而是对结点的两个子结点进行添加进队列和交换的操作。

这里利用队列的方法类似于二叉树的分层遍历所采用的方法。

  1. public static void mirrorBinary(BinaryTreeNode root){
  2. Queue<BinaryTreeNode> q = new LinkedList<BinaryTreeNode>();
  3. BinaryTreeNode temp = new BinaryTreeNode(0);
  4. if(root!=null){
  5. q.add(root);
  6. }
  7. while(q.size()>0){
  8. BinaryTreeNode node = q.poll();
  9. if(node.getLeft()!=null){
  10. q.add(node.getLeft());
  11. }
  12. if(node.getRight()!=null){
  13. q.add(node.getRight());
  14. }
  15. temp = node.getLeft();
  16. node.setLeft(node.getRight());
  17. node.setRight(temp);
  18. }
  19. }

面试题二十:顺时针打印矩阵(按圈打印)

  1. public class Test {
  2.  
  3. public static void main(String[] args){
  4. BinaryTreeNode root = new BinaryTreeNode(8);
  5. int[][] num = {{1,2,3,4},{5,6,7,8,},{1,3,5,7,},{2,4,6,8}};
  6. print(num,4,4);
  7. }
  8. public static void print(int[][] num,int rows,int columns){
  9. if(num==null||rows<=0||columns<=0){
  10. return;
  11. }
  12. int temp = 0;
  13. while(rows>temp*2&&columns>temp*2){
  14. printCircle(num,temp,rows,columns);
  15. temp++;
  16. }
  17. }
  18. private static void printCircle(int[][] num,int start,int rows,int columns) {
  19. int endRow = rows-1-start;
  20. int endColumn = columns-1-start;
  21. for(int i = start;i<=endColumn;i++){
  22. System.out.print(num[start][i]);
  23. }
  24. //如果行数大于起始值,那么肯定不止一行,所以最右一列可以打印
  25. if(start<endRow){
  26. for(int i = start+1;i<=endRow;i++){
  27. System.out.print(num[i][endRow]);
  28. }
  29. }
  30. //从右到左打印最下一行
  31. if(start<endRow&&start<endColumn){
  32. for(int i = endColumn-1;i>=start;i--){
  33. System.out.print(num[endRow][i]);
  34. }
  35. }
  36. //打印最左边一列
  37. if(start<endColumn&&start<endRow-1){
  38. for(int i =endRow-1;i>start;i--){
  39. System.out.print(num[i][start]);
  40. }
  41. }
  42. System.out.println(".......");
  43. }
  44. }

面试题二十一:包含min函数的栈

创建一个辅助栈,在每次存入新元素时,将新元素和辅助栈的栈顶元素相比,如果栈顶元素小,则再添加一次栈顶元素,否则添加新元素。这样可以保证辅助栈的栈顶始终都是原本栈中的最小元素。

  1. public class minStack {
  2.  
  3. private Stack<Integer> stack1;
  4. private Stack<Integer> stackHelp;
  5. private int temp,pop1,pop2;
  6. public minStack(){
  7. stack1 = new Stack<Integer>();
  8. stackHelp = new Stack<Integer>();
  9. }
  10. public void push(int num){
  11. stack1.push(num);
  12. if(stackHelp.size()==0||num<stackHelp.peek()){
  13. stackHelp.push(num);
  14. }else{
  15. stackHelp.push(stackHelp.peek());
  16. }
  17. }
  18. public void pop(){
  19. pop1 = stack1.pop();
  20. pop2 = stackHelp.pop();
  21. System.out.println("本栈是"+pop1+"辅助栈是"+pop2);
  22. }
  23. public void min(){
  24. System.out.println("最小值是"+stackHelp.pop());
  25. }
  26. }

面试题二十二:栈的压入,弹出序列

输入两组数,判断一个是否是另一个的弹栈顺序。比如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.   则第二个数组满足条件。

  1. public class Test {
  2.  
  3. public static void main(String[] args){
  4. int[] numPush = {1,2,3,4,5};
  5. int[] numPop = {4,3,5,2,1};
  6. System.out.println(isPopOrder(numPush,numPop));
  7. }
  8. public static boolean isPopOrder(int[] numPush,int[] numPop ){
  9.   if(numPush.length<=0||numPop.length<=0||numPush.length!=numPop.length){
                 return false;
             }
  10. Stack<Integer> stackPop = new Stack<Integer>();
  11. for(int i=numPop.length-1;i>=0;i--){
  12. stackPop.push(numPop[i]);
  13.  
  14. }
  15.  
  16. Stack<Integer> stackPush = new Stack<Integer>();
  17. int j = 0;
  18.  
  19. while(j<numPush.length){
  20. if(numPush[j]!=stackPop.peek()){
  21. stackPush.push(numPush[j]);
  22.  
  23. j++;
  24. }else{
  25. stackPush.push(numPush[j]);
  26. System.out.println(numPush[j]);
  27. while(stackPush.size()>0&&stackPop.size()>0&&stackPush.peek()==stackPop.peek()){
  28. System.out.println("..."+stackPush.pop());
  29. System.out.println(".."+stackPop.pop());
  30. }
  31. j++;
  32. }
  33. }
  34.  
  35. if(stackPush.size()==0){
  36. return true;
  37. }else{
  38.  
  39. return false;
  40. }
  41. }
  42.  
  43. }

面试题二十四:判断一个数组是否是某二叉树的后序遍历顺序

后续遍历结果最后一个是根节点,除去根节点,数组的前半部分应该都比根节点的值小,数组的后半部分应该都比根节点的值大,按照这个规律,递归判断。

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

  1. public static boolean isBinaryTree(int[] num ){
  2. if(num.length<=0){
  3. return false;
  4. }
  5. int root = num[num.length-1];
  6. int i = 0 ;
  7. for(;i<num.length-1;i++){
  8. if(num[i]>root){
  9. break;
  10. }
  11. }
  12.  
  13. for(int j =i;j<num.length-1;j++){
  14. if(num[j]<root){
  15. return false;
  16. }
  17. }
  18. int[] left = Arrays.copyOfRange(num, 0, i);
  19. int[] right = Arrays.copyOfRange(num, i, num.length-1);
  20.  
  21. Boolean isLeft = true;
  22. if(left.length>0){
  23. isBinaryTree(left);
  24. }
  25. Boolean isRight = true;
  26. if(right.length>0){
  27. isBinaryTree(right);
  28. }
  29. return(isLeft&&isRight);
  30.  
  31. }

面试题二十五:二叉树中和为某一值的路径

  1. public static void main(String[] args){
  2. BinaryTreeNode root = new BinaryTreeNode(5);
  3. BinaryTreeNode node1 = new BinaryTreeNode(4);
  4. BinaryTreeNode node2 = new BinaryTreeNode(3);
  5. BinaryTreeNode node3 = new BinaryTreeNode(5);
  6. BinaryTreeNode node4 = new BinaryTreeNode(1);
  7. BinaryTreeNode node5 = new BinaryTreeNode(2);
  8. BinaryTreeNode node6 = new BinaryTreeNode(1);
  9. root.setLeft(node1);
  10. root.setRight(node3);
  11. node1.setLeft(node2);
  12. node3.setLeft(node4);
  13. node3.setRight(node5);
  14. node4.setLeft(node6);
  15. Stack<Integer> stack = new Stack<Integer>();
  16. isPath(12,0,root,stack);
  17.  
  18. }
  19. public static void isPath(int expectSum,int currentSum,BinaryTreeNode root,Stack<Integer> stack){
  20. if(root==null){
  21. return;
  22. }
  23. stack.push(root.getValue());
  24. currentSum += root.getValue();
  25. if(root.getLeft()==null&&root.getRight()==null&&currentSum==expectSum){
  26. for(Integer e : stack){ //这种方式输出不用谈栈,元素还在栈里
  27. System.out.print(e+"\t");
  28. }
  29. System.out.println();
  30. }
  31. if(root.getLeft()!=null){
  32. isPath(expectSum,currentSum,root.getLeft(),stack);
  33. }
  34. if(root.getRight()!=null){
  35. isPath(expectSum,currentSum,root.getRight(),stack);
  36. }
  37. stack.pop(); //执行到叶结点(倒数第二层的左子结点)之后,pop,就会回到上一层,然后判断一下有没有右子结点,执行下一步没有的话,再pop,又往上一层,再检查右子结点。
  38.  
  39. }

面试题二十六:复制一个复杂链表

复杂链表:一个结点可以有两个指向,一个是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. 1 private BinaryTreeNode curNode ;
  2. 2 public void toTwo(BinaryTreeNode root){
  3. 3 if(root!=null){
  4. 4 toTwo(root.getLeft());
  5. 5 if(curNode!=null){
  6. 6 curNode.setLeft(root);
  7. 7 root.setRight(curNode);
  8. 8 }
  9. 9 curNode = root;
  10. 10 toTwo(root.getRight());
  11. }
  12. }

面试题二十八:字符串的排列

和八皇后问题一样,都是用 回溯法解决问题。

  1. public class Test {
  2.  
  3. private final int SET = 1;
  4. private final int UNSET = 0;
  5. private int size;
  6. private int[] set;
  7. private char[] c;
  8. private char[] location;
  9. private int count;
  10. public Test(int size,char[] c){
  11. this.size = size;
  12. this.c = c;
  13. location = new char[size];
  14. set = new int[size];
  15. }
  16. public void charSet(int i,int j,int k){
  17. location[i] = c[j];
  18. if(k==0){
  19. set[j] = UNSET;
  20. }
  21. }
  22. public int isPlace(int j){
  23. return set[j];
  24. }
  25. public void print(){
  26. System.out.println("第"+count+"种方法");
  27. for(int j=0;j<size;j++){
  28. System.out.print(location[j]+".");
  29. }
  30. System.out.println();
  31. }
  32. public void place(int i){
  33. for(int j = 0;j<size;j++){
  34. if(set[j]==UNSET){
  35. charSet(i,j,1);
  36. set[j] = SET;
  37. if(i<size-1){
  38. place(i+1);
  39. }else{
  40. count++;
  41. print();
  42. }
  43. charSet(i,j,0);
  44. }
  45. }
  46. }
  47. public static void main(String[] args){
  48. char[] c = {'a'};
  49. if(c==null){
  50. return;
  51. }
  52. else{
  53. Test t = new Test(c.length,c);
  54. t.place(0);
  55. }
  56. }
  57.  
  58. }

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

  1. public class Test {
  2. public static void main(String[] args){
  3. perm("abc");
  4.  
  5. }
  6. public static void perm(String s){
  7. List<String> result = new ArrayList<String>();
  8. for(int i =1;i<=s.length();i++){
  9. perm(s,i,result);
  10. }
  11. }
  12. public static void perm(String s,int m,List<String> result){
  13. if(s.length()<m){
  14. return;
  15. }
  16. if(m==0){
  17. for(int i =0;i<result.size();i++){
  18. System.out.println(result.get(i));
  19. }
  20. System.out.println();
  21. return;
  22. }else{
  23. if(s.length()!=0){
  24. result.add(s.charAt(0)+"");
  25. perm(s.substring(1,s.length()),m-1,result);
  26. result.remove(result.size()-1);
  27. perm(s.substring(1,s.length()),m,result);
  28. }
  29. }
  30. }
  31.  
  32. }

剑指offer编程题java实现(正在更新)的更多相关文章

  1. 剑指offer编程题Java实现——面试题5从头到尾打印链表

    题目描述* 剑指offer面试题5:从尾到头打印链表 输入一个链表的头结点,从尾到头打印出每个结点的值 解决方案一:首先遍历链表的节点后打印,典型的"后进先出",可以使用栈来实现这 ...

  2. 剑指offer编程题Java实现——面试题12相关题大数的加法、减法、乘法问题的实现

    用字符串或者数组表示大数是一种很简单有效的表示方式.在打印1到最大的n为数的问题上采用的是使用数组表示大数的方式.在相关题实现任意两个整数的加法.减法.乘法的实现中,采用字符串对大数进行表示,不过在具 ...

  3. 剑指offer编程题Java实现——面试题10二进制中1的个数

    题目: 请实现一个函数,输入一个整数,输出该整数二进制表示中1的个数.例如,把9表示成二进制是1001,有2位是1,该函数输出2解法:把整数减一和原来的数做与运算,会把该整数二进制表示中的最低位的1变 ...

  4. 剑指offer编程题Java实现——面试题7相关题用两个队列实现一个栈

    剑指offer面试题7相关题目:用两个队列实现一个栈 解题思路:根据栈的先入后出和队列的先入先出的特点1.在push的时候,把元素向非空的队列内添加2.在pop的时候,把不为空的队列中的size()- ...

  5. 剑指offer编程题Java实现——面试题7用两个栈实现队列

    题目:用两个栈实现一个队列.队列的声明如下:请实现他的两个函数appendTail和deleteHead, 分别完成在队列尾部插入节点和在队列头部删除节点的功能. package Solution; ...

  6. 剑指offer编程题Java实现——替换空格

    题目描述 请实现一个函数,将一个字符串中的空格替换成"%20".例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. package ...

  7. 剑指offer编程题Java实现——面试题6重建二叉树

    题目: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2, ...

  8. 剑指offer编程题Java实现——面试题11数值的整数次方

    题目: 实现函数double power(double base,int exponent),求base的exponent次方.不得使用库函数,同时不需要考虑大数问题. 解题思路:最一般的方法实现数值 ...

  9. 剑指offer编程题Java实现——面试题12打印1到最大的n位数

    题目:打印1到最大的n位数 输入数字n,按顺序打印输出从1到最大的n位十进制数,比如输入3,打印从1到999. 这道题考察的地方是如何表示大数问题.由于n是任意大的数组,如果n太大的话n位数就超过了l ...

  10. 剑指offer编程题Java实现——面试题14调整数组顺序使奇数位于偶数之前

    题目: 输入一个整数数组,实现一个函数来调整该数组中数组的顺序,使得所有的奇数位于数组的前半部分,偶数位于数组的后半部分. 解题思路:数组中维护两个指针,第一个指针初始化时候指向数组头部,第二个指针初 ...

随机推荐

  1. 用C++实现的解数独(Sudoku)程序

    我是一个C++初学者,控制台实现了一个解数独的小程序. 代码如下: //"数独游戏"V1.0 //李国良于2016年11月11日编写完成 #include <iostream ...

  2. JS 模块化和打包方案收集

    1.这里想讨论的是拆分规则,不是在问哪个工具怎么使用.2.这里没有在想找正确答案,因为感觉这个问题要结合具体业务场景. 随着项目开发越来越大,一开始代码全打包到一个文件的方式,让文件越来越大,接下来要 ...

  3. 海外建VPS并支持VPN

    推荐 DigitalOcean http://www.digitalocean.com/?refcode=7c26aea99ed6

  4. Optimal Flexible Architecture(最优灵活架构)

    来自:Oracle® Database Installation Guide 12_c_ Release 1 (12.1) for Linux Oracle base目录命名规范: /pm/s/u 例 ...

  5. Redis到底该如何利用(三)?

    上两篇受益匪浅,秉着趁热打铁,不挖到最深不罢休的精神,我决定追加这篇.上一篇里最后我有提到实现分级缓存管理应该是个可行的方案,因此今天特别实践了一下.不过缓存分级之后也发现了一些问题,例如下图: 当a ...

  6. TDD学习笔记【五】一隔绝相依性的方式与特性

    前言 在上一篇文章中,提到了如何通过 IoC 的设计,以及 Stub Object 的方式,来独立测试目标对象. 这一篇文章,则要说明有哪些设计对象的方式,可以让测试或需求变更时,更容易转换. 并说明 ...

  7. 数据分析(9):DataFrame介绍

    DataFrame 表格型的数据结构 创建DataFrame 可以通过传入dict的方式,DataFrame会自动加上索引,并且列会有序排列 data = {'state':['a', 'b', 'c ...

  8. jshint 一些选项(转载)

    内容来自: http://www.cnblogs.com/qianduanjingying/p/6185793.html 一些变量的作用: http://www.cnblogs.com/CloudMu ...

  9. 修改socket为keepAlive

    参考文章:http://blog.csdn.net/ctthuangcheng/article/details/8596818 [root@mdw- gpadmin]# vi /etc/sysctl. ...

  10. 布局包含Image和Title的UIButton

    UIButton中的titleEdgeInsets和imageEdgeInsets可以管理button中image和title的布局. 如果对其理解不够深入,用纯数字进行布局管理,经过不断的调试,还是 ...