题目2:实现Singleton模式
构造函数设为私有函数;饿汉式;懒汉式+同步锁;静态内部类; |
//饿汉式 class Singleton1{ private static Singleton1 s1= new Singleton1(); private Singleton1(){}; public static Singleton1 get(){ return s1; } }
//懒汉式_将get方法设为同步;
class Singleton1{ private static Singleton1 s1= null; private Singleton1(){}; public static synchronized Singleton1 get(){ if (s1 == null){ s1 = new Singleton1(); } return s1; } }
//懒汉式_同步代码块
class Singleton1{ volatile private static Singleton1 s1= null; private Singleton1(){}; public static Singleton1 get(){ if (s1 == null){ synchronized (Singleton1.class){ if (s1 == null){ s1 = new Singleton1(); } } } return s1; } }
//静态内部类
class Singleton1{ private Singleton1(){}; private static class Inner{ private static Singleton1 s1 = new Singleton1(); } public static Singleton1 get(){ return Inner.s1; } }
题目3_1:数组中重复的数字
解法1 | 对数组排序,再扫描数组;o(nlogn) |
解法2 | 额外增加一个o(n)的哈希表,遇到数字则存入哈希表,若已存在则遇到重复;时间复杂度o(n) |
解法3 | 因为数字限定在0-n-1的范围内,则可以将数字与下标对应,若遇到乱序则进行还原;时间复杂度o(n),空间复杂度o(1) |
public static int duplicate(int[] a){ //空数组 if (a.length == 0){ System.out.println("null array"); return -1; } for (int x = 0;x<a.length;x++){ int temp = a[x]; //包含0-(n-1)范围外的数字 if (temp>a.length-1){ System.out.print("error input"); return -1; } //当角标不等时 if (temp != x){ //已有 if (a[temp] == temp){ return temp; }else { a[x] = a[temp]; a[temp] = temp; System.out.println(Arrays.toString(a)); x -- ; } } } return -1; }
题目 3-2
额外o(n)的数组,依次将原数组复制至新数组对应下标,出现已有元素则找到重复 | o(n);o(n) |
将n个数二分,计算每部分在数组中出现的次数,必然有一边多于n/2,则重复出现在那边 | o(nlogn);o(1) |
public static int getDuplication(int[] a){ if (a == null || a.length == 0){ return -1; } int start = 1; int end = a.length - 1; while (start<=end){ int mid = (end-start)/2+start; int count = count(a,start,mid); if (start == end){ if (count>1){ return start; }else { break; } } if ( count > mid - start + 1){ end = mid; }else { start = mid+1; } } return -1; } public static int count(int[] a ,int start ,int end){ int count = 0; if (a == null || a.length == 0){ return count; } for (int x :a){ if (x>=start && x<=end){ count++; } } return count; }
题目 4
利用左下角或右上角减小需要判断的区域; |
public static boolean find(int[][] a,int num){ int hang = 0; int lie = a.length-1; if (a == null || a.length == 0){ return false; } while (hang <= a.length-1 && lie >= 0){ if (a[hang][lie] == num){ return true; } else if (a[hang][lie] < num){ hang++; } else if (a[hang][lie] > num){ lie--; } if (hang > a.length || lie < 0){ break; } } return false; }
题目 5_1
从头扫描字符串,遇到空格则后移后面的字符插入替换的字符 | o(n[2]) |
预算替换后的长度,用两个指针,一个指向字符串尾,一个指向预算长度尾,向前替换 | o(n) |
//java中String类型是不可变的,数组是不可直接扩容的,故这题无法直接在原字符串上进行替换
public static String replaceBlack(String a){ if (a ==null ||a.length() == 0){ return null; } StringBuilder sb = new StringBuilder(); for (int x = 0;x<a.length();x++){ if (a.charAt(x) == ' '){ sb.append("%20"); }else { sb.append(a.charAt(x)); } } return sb.toString(); }
题目5_2 合并两个有序数组
public static int[] combineArray(int[] a, int[] b){ //数组为空的情况 if (a == null || b == null){ return null; } //数组长度为0的情况 if (a.length == 0 || b.length == 0){ return a.length == 0 ? b:a; } ArrayList<Integer> c = new ArrayList<>(); int i = 0; int j = 0; while (i<a.length || j< b.length){ if (i == a.length && j<b.length){ c.add(b[j]); j++; } else if (i<a.length && j == b.length){ c.add(a[i]); i++; } else { if (a[i]>=b[j]){ c.add(b[j]); j++; }else { c.add(a[i]); i++; } } } int[] d = new int[c.size()]; for(int x = 0;x<d.length;x++){ d[x] = c.get(x); } return d; }
题目 6
用栈来进行暂存; | o(n);o(n) |
递归,每当访问一个节点首先输出后一个节点,链表过长会导致函数调用栈溢出; | o(1);o(n) |
//用的是自己写的链表,用的时候才发现当时漏掉了好多函数;
public static void PrintListReversingly_Iteratively(MyLinkList my){ Stack<MyLinkList.Node> st = new Stack<>(); MyLinkList.Node no = MyLinkList.getRoot(); while (MyLinkList.getNext(no)!= null){ MyLinkList.Node next = MyLinkList.getNext(no); st.push(next); no = next; } while (st.isEmpty() != true){ System.out.print(st.pop().data); } }
public static void PrintListReversingly_Recursively(MyLinkList.Node e){ if (e != null){ if ( MyLinkList.getNext(e) != null){ PrintListReversingly_Recursively(MyLinkList.getNext(e)); } System.out.print(e.data); } }
题目7
递归的思想构建,每次返回子树根节点 |
public static Tree.Node Construct(int[] preorder ,int[] inorder){ if (preorder == null || inorder == null || preorder.length == 0 || inorder.length == 0|| preorder.length != inorder.length){ return null; } Tree.Node temp = Tree.newNode(preorder[0]); for (int i = 0;i<inorder.length;i++){ if (preorder[0] == inorder[i]){ temp.leftchild = Construct(Arrays.copyOfRange(preorder,1,i+1),Arrays.copyOfRange(inorder,0,i)); temp.rightchild = Construct(Arrays.copyOfRange(preorder,i+1,preorder.length),Arrays.copyOfRange(inorder,i+1,inorder.length)); } } return temp; }
题目8 二叉树的下一个节点
分类讨论;若存在右子树,则下一个节点为右子树的最左节点;若无且当前节点为父节点的左节点,则为父节点;若为右节点,则向上找一个为左子节点的父亲的父亲; |
public class test { public static void main(String[] args) { Node[] nodes = new Node[9]; for(int i = 0;i<9;i++){ nodes[i] = new Node(i); } nodes[0].leftchild = nodes[1]; nodes[0].rightchild = nodes[2]; nodes[1].father = nodes[0]; nodes[1].leftchild = nodes[3]; nodes[1].rightchild = nodes[4]; nodes[2].father = nodes[0]; nodes[2].leftchild = nodes[5]; nodes[2].rightchild = nodes[6]; nodes[3].father = nodes[1]; nodes[4].father = nodes[1]; nodes[4].leftchild = nodes[7]; nodes[4].rightchild = nodes[8]; nodes[5].father = nodes[2]; nodes[6].father = nodes[2]; nodes[7].father = nodes[4]; nodes[8].father = nodes[4]; print(nodes[0]); System.out.print("\n"); System.out.println(getNext(nodes[6]).data); } public static void print(Node e){ if (e == null){ return; } if (e.leftchild != null){ print(e.leftchild); } System.out.print(e.data); print(e.rightchild); } public static Node getNext(Node e){ if (e == null){ return null; } if (e.rightchild != null){ Node temp = e.rightchild; while (temp.leftchild != null){ temp = temp.leftchild; } return temp; }else { if (e.father.leftchild == e){ return e.father; }else { while (e.father != null && e.father.father.leftchild != e.father){ e = e.father; } return e.father; } } } } class Node{ int data; Node(int num){ this.data = num; } Node leftchild; Node rightchild; Node father; }
面试题9_1
stack2为空时,stack1弹出所有元素并压入stack2;stack2不为空时,直接弹出stack2的栈顶; |
class CQueue{ private static Stack<Integer> e1 = new Stack(); private static Stack<Integer> e2 = new Stack(); public static void appendTail(int num){ e1.push(num); } public static int deleteHead() throws Exception{ if (e2.isEmpty() == true){ while (e1.isEmpty() != true){ e2.push(e1.pop()); } } if (e2.isEmpty() == true){ throw new Exception("queue is empty"); } return e2.pop(); } }
面试题9_2
扫描二维码关注公众号,回复:
921381 查看本文章
维持一个队列为空,每次弹出是将1-(n-1)的元素移动至另一队列中; |
class Cstack{ private static ArrayDeque<Integer> q1 = new ArrayDeque<>(); private static ArrayDeque<Integer> q2 = new ArrayDeque<>(); public static void push(int num){ if (q1.isEmpty() != true){ q1.add(num); }else { q2.add(num); } } public static int pop() throws Exception{ if (q1.isEmpty() != true){ int temp = 0; while (temp<q1.size()-1){ q2.add(q1.poll()); } return q1.poll(); }else { if (q2.isEmpty() == true){ throw new Exception("empty"); } int temp = 0; while (temp<q2.size()-1){ q1.add(q2.poll()); } return q2.poll(); } } }
面试题10_1
自底向上计算,避免重复计算 | o(n) |
利用公式化解计算 | o(log[n]) |
public static int Fibonacci(int num){ int f0 = 0; int f1 = 1; int temp = f0+f1; for (int x = 0;x<num-1;x++){ temp = f0+f1; f0 = f1; f1 = temp; } return num == 0?f0:temp; }
面试题10_2
n = 1时只有一种跳法;n = 2时2钟;n时,可以选择前一步为只走1步,也可以选择前一步只走2步,f(n) = f(n-1)+f(n-2); |
面试题10_3
f(8) = 竖着放一个小矩形:f(7)+横着放两个小矩形+f(6) |
面试题11
最小值刚好位于两个有序数组的分界处,可以用二分查找的思想进行范围的缩小;当尾指针=头指针=中间指针时,只能进行顺序查找;o(log[n]) |
public static int Min(int[] a){ if ( a == null || a.length == 0){ return -1; } int i = 0; int j = a.length-1; int mid = 0; while (a[i]>=a[j]){ if (j-i == 1){ mid =j; break; } mid = (i+j)/2; if (a[i] == a[j] && a[i] == a[mid]){ return MinInOrder(a,i,j); } if (a[i]<=a[mid]){ i = mid; } else if (a[j]>=a[mid]){ j = mid; } } return a[mid]; } public static int MinInOrder(int[] a, int i,int j){ int re = a[i]; for(int x = i;x<=j;x++){ if ( re > a[x] ){ re = a[x]; } } return re; }
面试题12:矩阵中的路径
遍历矩阵选择点;判断该点是否可作为字符串开头;若可作为开头,递归的查看其4个方向的点是否在字符串中; |
public static boolean hasPath(char[][] matrix,char[] str){ if (matrix == null || str == null){ return false; } int rows = matrix.length; if (rows == 0){ return false; } int cols = matrix[0].length; if (cols == 0){ return false; } boolean[][] visited = new boolean[rows][cols]; int pathLenth = 0; for (int x = 0;x<rows;x++){ for (int y = 0; y<cols;y++){ if (hasPathCore(matrix,rows,cols,x,y,str,pathLenth,visited) == true){ return true; } } } return false; } public static boolean hasPathCore(char[][] matrix,int rows,int cols,int x,int y,char[] str,int pathlenth,boolean[][] visited){ if (str.length == pathlenth){ return true; } boolean hasPath = false; if (x>=0 && x<rows && y>=0 && y<cols && matrix[x][y] == str[pathlenth] && visited[x][y] == false){ pathlenth++; visited[x][y] = true; hasPath = hasPathCore(matrix,rows,cols,x,y+1,str,pathlenth,visited) || hasPathCore(matrix,rows,cols,x,y-1,str,pathlenth,visited) || hasPathCore(matrix,rows,cols,x-1,y,str,pathlenth,visited) || hasPathCore(matrix,rows,cols,x+1,y,str,pathlenth,visited); if (hasPath == false){ pathlenth --; visited[x][y] = false; } } return hasPath; }
面试题13:机器人的运动范围
可达点的周围也必然有可达点;从(0,0)开始,进行递归的扫描; |
public static int getDigitSum(int number){ int sum = 0; while (number > 0){ sum += number%10; number /= 10; } return sum; } public static boolean check(int threshold,int rows,int cols,int row,int col,boolean[][] visited){ if (row>=0 && row<rows && col>=0 && col<cols && (getDigitSum(row)+getDigitSum(col))>threshold && visited[row][col] == false){ return true; } return false; } public static int movingCount(int threshold,int rows,int cols){ if (threshold<0 || rows<0 || cols<0){ return 0; } boolean[][] visited = new boolean[rows][cols]; return movingCountCore(visited,threshold,rows,cols,0,0); } public static int movingCountCore(boolean[][] visited,int threshold,int rows,int cols,int row,int col){ int count = 0; if (check(threshold,rows,cols,row,col,visited) == true){ visited[row][col] = true; count = 1+ movingCountCore(visited,threshold,rows,cols,row,col+1)+movingCountCore(visited,threshold,rows,cols,row,col-1)+ movingCountCore(visited,threshold,rows,cols,row-1,col)+movingCountCore(visited,threshold,rows,cols,row+1,col); } return count; }
面试题14:剪绳子
动态规划 f(n) = max{f(i) * f(n-i)}; | o(n[2]);o(n); |
贪婪算法 尽量多剪长度为3的,剩下长度为4时,剪成两个长度为2 | o(1) |
public static int maxProductAfterCutting_solution1(int lenth){ if (lenth<2){ return 0; }else if (lenth == 2){ return 1; }else if (lenth == 3){ return 2; } int[] products = new int[lenth+1]; //用于乘的组件 product[4]过后才是记录的值 products[1] = 1; products[2] = 2; products[3] = 3; for (int x = 4;x <= lenth;x++){ int max = 0; for (int y = 1;y <= x/2;y++){ int product = products[y]*products[x-y]; if (max<product){ max = product; } } products[x] = max; } return products[lenth]; }
public static int maxProductAfterCutting_solution2(int length){ if (length<2){ return 0; }else if (length == 2){ return 1; }else if (length == 3){ return 2; } int timesOf3 = length/3; if (length - timesOf3*3 == 1){ timesOf3 = timesOf3 -1; } int timesof2 = (length - timesOf3*3)/2; return (int)(Math.pow(3,timesOf3) * Math.pow(2,timesof2)); }
面试题15_1:二进制中1的个数
在电脑中存储的是二进制的树;可以通过与1进行某位的判断;可以通过n&(n-1)将最右的1置0; |
public static int NumberOf1(int n){ int count = 0; while (n!=0){ count++; n = n & (n-1); } return count; }
面试题15_2:
若一个整数是2的整数次方,则其二进制表示中只有1位为1; |
public static boolean if2(int num){ if ( num <= 0){ return false; } if ( (num & (num-1)) == 0){ return true; } return false; }
面试题15_3:
求两个数二进制表示中不同的位的个数;求异或,再计算1的个数; |
public static int diff(int num1,int num2){ int num3 = num1 ^ num2; int count = 0; while (num3 != 0){ count = count+1; num3 = num3 & (num3-1); } return count; }