面试题目15:三数之和
将数组排序,遍历数组,以当前数为第一个数,在后面的序列中寻找剩余的两个数(头尾指针方式)。注意当前数大于0则可结束,且需要跳过重复的数。 |
public static List<List<Integer>> threeSum(int[] nums) { List<List<Integer>> lists = new ArrayList<>(); if (nums == null || nums.length<=2){ return lists; } Arrays.sort(nums); for (int x = 0;x<=nums.length-3;x++){ if (nums[x]>0){ return lists; } if (x>0 && nums[x] == nums[x-1]){ continue; } find(nums,x+1,nums.length-1,nums[x],lists); } return lists; } public static void find(int[] nums,int start,int end,int number,List<List<Integer>> lists){ while (start<end){ int temp =nums[start] + nums[end] + number; if (temp == 0){ List<Integer> thistime = new ArrayList<>(); thistime.add(nums[start]); thistime.add(nums[end]); thistime.add(number); lists.add(thistime); while (start<end && nums[start+1] == nums[start]){ start++; } start++; while (start<end && nums[end-1] == nums[end]){ end--; } end--; }else if (temp<0){ start++; }else { end--; } } }
面试题73:矩阵置0
用第一行及第一列来记录出现0的行列,首先记录下第一行第一列是否有0。 |
public static void setZeroes(int[][] matrix) { if (matrix == null || matrix.length == 0||matrix[0].length == 0){ return; } int row = matrix.length; int col = matrix[0].length; for (int x = 0;x<=row-1;x++){ for (int y = 0;y<=col-1;y++){ if (matrix[x][y] == 0){ reset(matrix,x,y,row,col); } } } for (int x = 0;x<=row-1;x++){ for (int y = 0;y<=col-1;y++){ if (matrix[x][y] ==Integer.MIN_VALUE){ matrix[x][y] = 0; } } } } public static void reset(int[][] matrix,int x,int y,int row,int col){ for (int i = 0;i<=col-1;i++){ if (matrix[x][i]!=0){ matrix[x][i] = Integer.MIN_VALUE; } } for (int i = 0;i<=row-1;i++){ if (matrix[i][y]!=0){ matrix[i][y] = Integer.MIN_VALUE; } } }
面试题49:字母异位词分组
遍历字符串数组,用hashmap辅助,每读一个就将其字符串排序,不存在则添加,存在则添加其下标,再遍历hashmap生成返回答案 |
public static List<List<String>> groupAnagrams(String[] strs) { List<List<String>> lists = new ArrayList<>(); if (strs == null){ return lists; } HashMap<String,ArrayList<Integer>> hashMap = new HashMap<>(); for (int x = 0;x<=strs.length-1;x++){ char[] temp = strs[x].toCharArray(); Arrays.sort(temp); String temp_st = String.valueOf(temp); if (hashMap.containsKey(temp_st)){ hashMap.get(temp_st).add(x); }else { ArrayList<Integer> group = new ArrayList<>(); group.add(x); hashMap.put(temp_st,group); } } for (ArrayList<Integer> temp :hashMap.values()){ List<String> group = new ArrayList<>(); for (int x: temp){ group.add(strs[x]); } lists.add(group); } return lists; }
面试题3:无重复字符的最长子串
遍历字符串,不断更新子串及最大长度 |
public static int lengthOfLongestSubstring(String s) { if (s == null || s.length() == 0){ return 0; } StringBuilder stringBuilder = new StringBuilder(); int max = 0; int substring = 0; char[] s_char = s.toCharArray(); for (int x = 0;x<=s_char.length-1;x++){ if (stringBuilder.indexOf(String.valueOf(s_char[x])) == -1){ stringBuilder.append(s_char[x]); substring++; }else { int lastindex = stringBuilder.lastIndexOf(String.valueOf(s_char[x])); stringBuilder.delete(0,lastindex+1); stringBuilder.append(s_char[x]); substring = stringBuilder.length(); } if (max<substring){ max = substring; } } return max; }
面试题5:最长回文子串
动态规划求解,p[i.j] = true when p[i+1,j-1] = true && p[i] = p[j] |
public static String longestPalindrome(String s) { if (s == null || s.length() == 0){ return ""; } int start = 0; int maxlenth = 0; boolean[][] palindrome = new boolean[s.length()][s.length()]; char[] s_char = s.toCharArray(); for (int x = 0;x<=s_char.length-1;x++){ palindrome[x][x] = true; if (x<s_char.length-1 && s_char[x] == s_char[x+1]){ palindrome[x][x+1] = true; start = x; maxlenth = 2; } } if (maxlenth == 0){ maxlenth = 1; start = 0; } for (int x = 3;x<=s_char.length;x++){ for (int y = 0;y<=s_char.length-x;y++){ int end = y+x-1; if (palindrome[y+1][end-1] && s_char[y] == s_char[end]){ palindrome[y][end] = true; maxlenth = x; start = y; } } } if (maxlenth>0){ return s.substring(start,start+maxlenth); } return ""; }
面试题334:递增的三元子序列
用两个指针,当当前数小于第一个指针时,第一个指针变为当前数,当前数小于第二个指针时,第二个指针变为当前数,第一个指针维护最小值,第二个指针维护较小值,当前数大于第二个指针时,说明存在第三个数,输出true。 |
public static boolean increasingTriplet(int[] nums) { if (nums == null || nums.length <=2){ return false; } int index1 = Integer.MAX_VALUE; int index2 = Integer.MAX_VALUE; for (int x = 0;x<=nums.length-1;x++){ if (index1>nums[x]){ index1 = nums[x]; }else if (nums[x]>index1 && nums[x]<index2){ index2 = nums[x]; }else if (nums[x]>index2){ return true; } } return false; }
面试题2:两数相加
按位相后走,注意进位问题 |
public static ListNode addTwoNumbers(ListNode l1, ListNode l2) { if(l1 == null || l2 == null){ return null; } ListNode head = new ListNode(-1); ListNode rem = head; int carry = 0; while (l1!=null && l2!=null){ int temp = l1.val+l2.val+carry; if (temp > 9){ carry = 1; temp = temp-10; }else { carry = 0; } ListNode tp = new ListNode(temp); rem.next = tp; rem = rem.next; l1 = l1.next; l2 = l2.next; } while (l1!=null){ int temp = l1.val+carry; if (temp > 9){ carry = 1; temp = temp-10; }else { carry = 0; } ListNode tp = new ListNode(temp); rem.next = tp; rem = rem.next; l1 = l1.next; } while (l2!=null){ int temp = l2.val+carry; if (temp > 9){ carry = 1; temp = temp-10; }else { carry = 0; } ListNode tp = new ListNode(temp); rem.next = tp; rem = rem.next; l2 = l2.next; } if (carry == 1){ ListNode tp = new ListNode(1); rem.next = tp; } return head.next; }
面试题328:奇偶链表
用两个指针,一个指向奇数,一个指向偶数,把偶数后出现的奇数移到目前的奇数后面,再将两个指针分别移动一位,此时偶数指针再次指向偶数位置。 |
public static ListNode oddEvenList(ListNode head) { if (head == null || head.next == null){ return head; } ListNode odd = head; ListNode even = head.next; while (even!= null && even.next!=null){ ListNode temp = even.next; even.next = even.next.next; temp.next = odd.next; odd.next = temp; odd = odd.next; even = even.next; } return head; }
面试题160:相交链表
计算两个的长度,调整为相同,再顺序遍历 |
分别遍历,当某链表读完后跳到另外一条的头继续开始读,最后会在交点相遇或在结尾(null)相遇 |
public static ListNode getIntersectionNode(ListNode headA, ListNode headB) { if (headA == null || headB == null){ return null; } int lenthA = getlenth(headA); int lenthB = getlenth(headB); int dif = lenthA > lenthB ? lenthA-lenthB:lenthB-lenthA; ListNode first = headA; ListNode second = headB; if (lenthA > lenthB){ for (int x = 1;x<=dif;x++){ first = first.next; } }else { for (int x = 1;x<=dif;x++){ second = second.next; } } while (first!=null){ if (first.val == second.val){ return first; } first = first.next; second = second.next; } return null; } public static int getlenth(ListNode temp){ int lenth = 0; while (temp!=null){ lenth++; temp = temp.next; } return lenth; }
面试题94:二叉树的中序遍历(不用递归)
用栈来辅助,左节点入栈,出栈时访问节点,若有右节点,再入栈,继续找其左节点,按左中右访问 |
用两个指针,需要把空右节点指向中序遍历中的下一位。 |
public static List<Integer> inorderTraversal(TreeNode root) { List<Integer> reback = new ArrayList<>(); if (root == null){ return reback; } Stack<TreeNode> stack = new Stack<>(); TreeNode temp = root; while (temp!=null || stack.size()!=0){ while (temp!=null){ stack.push(temp); temp = temp.left; } TreeNode now = stack.pop(); reback.add(now.val); temp = now.right; } return reback; }
面试题103:二叉树的锯齿形层次遍历
用两个队列,第一个队列存这一层的,另一个队列存下一层的,注意加入左右节点的顺序 |
public static List<List<Integer>> zigzagLevelOrder(TreeNode root) { List<List<Integer>> lists = new ArrayList<>(); if (root == null){ return lists; } ArrayDeque<TreeNode> arrayDeque = new ArrayDeque<>(); arrayDeque.addLast(root); ArrayDeque<TreeNode> temp = new ArrayDeque<>(); int flag = 0; List<Integer> layer = new ArrayList<>(); while (arrayDeque.size()!=0){ TreeNode now = arrayDeque.pollLast(); layer.add(now.val); if (flag == 0){ if (now.left!=null){ temp.addLast(now.left); } if (now.right!=null){ temp.addLast(now.right); } }else { if (now.right!=null){ temp.addLast(now.right); } if (now.left!=null){ temp.addLast(now.left); } } if (arrayDeque.size()==0){ ArrayDeque<TreeNode> exchange = temp; temp = arrayDeque; arrayDeque = exchange; flag = 1-flag; lists.add(layer); layer = new ArrayList<>(); } } return lists; }
面试题105:从前序和中序遍历构建树(剑指offer写过)
递归,指针可优化,这里我写的用了hashmap |
public static TreeNode buildTree(int[] preorder, int[] inorder) { if (preorder == null || inorder == null || preorder.length!=inorder.length ||preorder.length == 0){ return null; } HashMap<Integer,Integer> hashMap = new HashMap<>(); for (int x = 0;x<=preorder.length-1;x++){ hashMap.put(preorder[x],x); } TreeNode root =buildtree_core(hashMap,inorder,0,inorder.length-1); return root; } public static TreeNode buildtree_core(HashMap<Integer,Integer> preorder,int[] inorder,int start,int end){ if (start > end){ return null; } int index = firstone(preorder,inorder,start,end); // System.out.print(index); TreeNode root = new TreeNode(inorder[index]); TreeNode left = buildtree_core(preorder,inorder,start,index-1); TreeNode right = buildtree_core(preorder,inorder,index+1,end); root.left = left; root.right = right; return root; } public static int firstone(HashMap<Integer,Integer> preorder,int[] inorder,int start,int end){ int min = inorder.length; int reback = start; for (int x = start;x<=end;x++){ int index = preorder.get(inorder[x]); if (index<min){ min = index; reback = x; } } return reback; }
面试题116:填充同一层的兄弟节点
子树之间的节点连接可以借助上层父节点之间的next指针 |
public static void connect(TreeLinkNode root) { if (root == null){ return; } root.next = null; if (root.left!=null){ root.left.next = root.right; root.right.next = null; } connect_core(root.left); connect_core(root.right); } public static void connect_core(TreeLinkNode root){ if (root== null || root.left == null){ return; } root.left.next = root.right; if (root.next!=null){ root.right.next = root.next.left; }else { root.right.next = null; } connect_core(root.left); connect_core(root.right); }
面试题230:二叉搜索树中第k小的元素
二叉搜索树的中序遍历是有序的,也可以通过子树节点个数来判断 |
public static int kthSmallest(TreeNode root, int k) { if (root == null || k<=0){ return -1; } ArrayList<Integer> nums = new ArrayList<>(); getNums(root,nums); return nums.get(k-1); } public static void getNums(TreeNode root,ArrayList<Integer> array){ if (root == null){ return; } getNums(root.left,array); array.add(root.val); getNums(root.right,array); }
面试题200:岛屿的个数
遍历数组,每遇到一个1,就将岛屿数+1,将该1置位0,且将周围的1都置为0,再去找下一个1; |
public static int numIslands(char[][] grid) { int lands = 0; if (grid == null || grid.length == 0 || grid[0].length == 0){ return lands; } for (int x = 0;x<=grid.length-1;x++){ for (int y = 0;y<=grid[0].length-1;y++){ if (grid[x][y] == '1'){ numIsland_core(grid,x,y); lands++; } } } return lands; } public static void numIsland_core(char[][] grid,int x ,int y){ grid[x][y] = '0'; if (x>0 && grid[x-1][y] == '1'){ numIsland_core(grid,x-1,y); } if (y>0 && grid[x][y-1] == '1'){ numIsland_core(grid,x,y-1); } if (x<grid.length-1 && grid[x+1][y] == '1'){ numIsland_core(grid,x+1,y); } if (y<grid[0].length-1 && grid[x][y+1] == '1'){ numIsland_core(grid,x,y+1); } }
面试题17:电话号码的字母组合
递归,需要传递给下一次,下次需要填的位置,已有的字符串。 |
public static List<String> letterCombinations(String digits) { List<String> reback = new ArrayList<>(); if (digits == null || digits.length() == 0){ return reback; } String[] nums = {"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"}; letter_core(digits,nums,0,"",reback); return reback; } public static void letter_core(String digits,String[] nums,int start,String res,List<String> reback){ if (start == digits.length()){ reback.add(res); return; } String str = nums[digits.charAt(start)-'0'-2]; for (int x = 0;x<=str.length()-1;x++){ String temp = res+str.charAt(x); letter_core(digits,nums,start+1,temp,reback); } }
面试题22:括号生成
递归,用左右括号的数量进行控制,若左括号数量小于右括号会出现错误情况,当剩余括号数为0,则添加字符串,注意不要改动当层的string,在传入参数时直接改动 |
public static List<String> generateParenthesis(int n) { List<String> reback = new ArrayList<>(); if (n<=0){ return reback; } int left = n; int right = n; core(n,n,reback,""); return reback; } public static void core(int left,int right,List<String> reback,String string){ if (left>right){ return; }else if (left == 0 && right == 0){ reback.add(string); return; } if (left>0){ core(left-1,right,reback,string+'('); } if (right>0){ core(left,right-1,reback,string+')'); } }
面试题46:全排列
递归问题,每次循环时需要检查当前数是否已出现过 |
public static List<List<Integer>> permute(int[] nums) { List<List<Integer>> lists = new ArrayList<>(); if (nums == null || nums.length == 0){ return lists; } core(nums,0,lists,""); return lists; } public static void core(int[] nums,int start,List<List<Integer>> lists,String temp){ if (start == nums.length){ List<Integer> list = new ArrayList<>(); String[] strings = temp.split(","); for (String s :strings){ if (s.length()!=0){ list.add(Integer.valueOf(s)); } } lists.add(list); return; } for (int x = 0;x<=nums.length-1;x++){ boolean cando = true; String[] strings = temp.split(","); for (String s :strings){ if (s.equals( String.valueOf(nums[x]))){ cando = false; } } if (cando) { core(nums, start + 1, lists, temp + String.valueOf(nums[x]) + ','); } } }
面试题78:子集
可以用递归的方法,不断地从剩余的数中选择数。需要传递还需选择的个数,开始角标,已选择的数,在插入时需要判断是否已有此集合 |
public static List<List<Integer>> subsets(int[] nums) { List<List<Integer>> lists = new ArrayList<>(); if (nums == null || nums.length == 0){ return lists; } int lenth = nums.length; for (int x = 0;x<=lenth;x++){ core(nums,x,0,lists,""); } return lists; } public static void core(int[] nums,int needchoose,int start,List lists,String temp){ String[] strings = temp.split(":"); List<Integer> st = new ArrayList<>(); for (String x:strings){ if (x.length()!=0){ st.add(Integer.valueOf(x)); } } if (needchoose == 0){ Collections.sort(st); if (!lists.contains(st)){ lists.add(st); } return; } for (int x = start;x<=nums.length-1;x++){ if (!st.contains(nums[x])){ core(nums,needchoose-1,start+1,lists,temp+String.valueOf(nums[x])+':'); } } }
面试题79:单词搜索
递归,向上下左右,需要传递当前坐标,匹配到的位数,访问下一位时,此位需要替换成其他符号,避免重复访问 |
public static boolean exist(char[][] board, String word) { if (board == null || word == null || board.length == 0 || board[0].length == 0 || word.length() == 0){ return false; } int row = board.length; int col = board[0].length; boolean reback = false; for (int x = 0;x<=row-1;x++){ for (int y = 0;y<=col-1;y++){ reback = core(board,row,col,x,y,word,0); if (reback){ return reback; } } } return reback; } public static boolean core(char[][] board,int row,int col,int nowrow,int nowcol,String word,int index){ if (index == word.length()){ return true; } if (nowrow>=row || nowcol>=col || nowrow<0 || nowcol<0){ return false; } boolean reback = false; if (board[nowrow][nowcol] == word.charAt(index)){ char temp = board[nowrow][nowcol]; board[nowrow][nowcol] = '*'; reback = (core(board,row,col,nowrow-1,nowcol,word,index+1) || core(board,row,col,nowrow+1,nowcol,word,index+1) || core(board,row,col,nowrow,nowcol-1,word,index+1) || core(board,row,col,nowrow,nowcol+1,word,index+1)); if (!reback){ board[nowrow][nowcol] = temp; } } return reback; }
面试题75:分类颜色
start指针维护0的位置,end指针维护2的位置,遍历数组,若扫描到0,与start交换,并start++,若扫描到1,则继续,若扫描到2,则与end交换,end--,此时交换回来的数可能是0,1,2,x指针也需回退一格。 |
public static void sortColors(int[] nums) { if (nums == null || nums.length <=1){ return; } int start = 0; int end = nums.length-1; for (int x = 0;x<=end;x++){ if (nums[x] == 0){ swap(nums,start,x); start++; }else if(nums[x] == 2){ swap(nums,end,x); x--; end--; } } } public static void swap(int[] nums,int index1,int index2){ int temp = nums[index1]; nums[index1] = nums[index2]; nums[index2] = temp; }
面试题347:前k个高频元素
先用hashmap存下数量,再用堆排序进行排序(priorityqueue) |
public static List<Integer> topKFrequent(int[] nums, int k) { List<Integer> list = new ArrayList<>(); if (nums == null || nums.length == 0 || k<=0 || k>nums.length){ return list; } HashMap<Integer,Integer> hashMap = new HashMap<>(); for (int x : nums){ if (hashMap.containsKey(x)){ hashMap.put(x,hashMap.get(x)+1); }else { hashMap.put(x,1); } } if (k>hashMap.size()){ return list; } PriorityQueue<Map.Entry<Integer,Integer>> priorityQueue = new PriorityQueue<>(new Comparator<Map.Entry<Integer,Integer>>() { @Override public int compare(Map.Entry<Integer,Integer> o1, Map.Entry<Integer,Integer> o2) { if (o1.getValue()>o2.getValue()){ return -1; }else if (o1.getValue()<o2.getValue()){ return 1; }else { return 0; } } }); for (Map.Entry<Integer,Integer> x:hashMap.entrySet()){ priorityQueue.add(x); } for (int x = 0; x<=k-1;x++){ Map.Entry<Integer,Integer> temp = priorityQueue.poll(); list.add(temp.getKey()); priorityQueue.remove(temp); } return list; }
面试题215:数组的第k个最大元素
排序,然后找 |
利用快排的算法,若排了之后刚好在第k-1位则找到,若大于,则说明在其左边,小于在其右边 |
public static int findKthLargest(int[] nums, int k) { if (nums == null || nums.length == 0 || k <=0 || k>nums.length){ return -1; } TreeMap<Integer,Integer> treeMap = new TreeMap<>(); for (int x : nums){ if (treeMap.containsKey(x)){ treeMap.put(x,treeMap.get(x)+1); }else { treeMap.put(x,1); } } while (k>0){ Map.Entry<Integer,Integer> temp = treeMap.lastEntry(); int next = k-temp.getValue(); if (next <= 0){ return temp.getKey(); }else{ treeMap.remove(temp.getKey()); k = next; } } return -1; }
面试题162:寻找峰值
二分查找,峰值一定存在 |
public static int findPeakElement(int[] nums) { if (nums == null || nums.length == 0){ return -1; } int start = 0; int end = nums.length-1; while (start<=end){ int mid = (end+start)/2; boolean peak = false; if (mid == 0){ if (mid != nums.length-1){ peak = check(nums,mid,mid+1); if (peak){ return mid; } start = mid+1; }else { return mid; } }else { if (mid == nums.length-1){ peak = check(nums,mid,mid-1); if (peak){ return mid; } end = mid-1; }else { peak = check(nums,mid,mid-1) && check(nums,mid,mid+1); if (peak){ return mid; } if (nums[mid-1]>nums[mid]){ end = mid-1; }else if (nums[mid+1]>nums[mid]){ start = mid+1; } } } } return -1; } public static boolean check(int[] nums ,int index1,int index2){ if (nums[index1] > nums[index2]){ return true; }else { return false; } }
面试题34:搜索范围
二分查找,然后向周边找范围 |
public static int[] searchRange(int[] nums, int target) { int[] reback = {-1,-1}; if (nums == null || nums.length == 0){ return reback; } int pre = 0; int after = nums.length-1; while (pre <= after){ int mid = (pre+after)/2; if (nums[mid] == target){ int start = mid; int end = mid; while (start>=0){ if (nums[start] == nums[mid]){ if (start == 0){ reback[0] = 0; break; } start--; }else { reback[0] = start+1; break; } } while (end<=nums.length-1){ if (nums[end] == nums[mid]){ if (end == nums.length-1){ reback[1] = nums.length-1; break; } end++; }else { reback[1] = end-1; break; } } return reback; }else if (nums[mid]<target){ pre = mid+1; }else { after = mid-1; } } return reback; }
面试题56:合并区间
先需要将区间排序,然后遍历,如果出现重叠,再进行合并; |
public static List<Interval> merge(List<Interval> intervals) { List<Interval> list = new ArrayList<>(); if (intervals == null || intervals.size() == 0){ return list; }else if (intervals.size() == 1){ return intervals; } PriorityQueue<Interval> priorityQueue = new PriorityQueue<>(new Comparator<Interval>() { @Override public int compare(Interval o1, Interval o2) { if (o1.start > o2.start){ return -1; }else if (o1.start < o2.start){ return 1; }else { return 0; } } }); for (Interval x :intervals){ priorityQueue.add(x); } Interval first = priorityQueue.poll(); int start = first.start; int end = first.end; for (int x = 1;x<=intervals.size()-1;x++){ Interval temp = priorityQueue.poll(); if (temp.start<=end && temp.end >= start){ start = start<temp.start?start:temp.start; end = end>temp.end?end:temp.end; } else { Interval another = new Interval(start,end); list.add(another); start = temp.start; end = temp.end; } if (x == intervals.size()-1){ Interval another = new Interval(start,end); list.add(another); } } return list; }
面试题33:搜索旋转排序数组
数组变成了两段递增的数组,可以通过mid与0的值判断其是左边有序还是右边有序,进而进行判断选择在哪边进行下一次选择 |
public static int search(int[] nums, int target) { if (nums == null || nums.length == 0){ return -1; } int start = 0; int end = nums.length-1; while (start <= end){ int mid = (start+end)/2; if (nums[mid] == target){ return mid; } if (nums[mid] >= nums[0]){ if (nums[0] <= target && nums[mid] > target){ end = mid-1; }else { start = mid+1; } }else { if (nums[mid] <target && nums[nums.length-1] >=target){ start = mid+1; }else { end = mid-1; } } } return -1; }
面试题240:搜索二维矩阵
左上角或右下角的可以作为二分的分点 |
public static boolean searchMatrix(int[][] matrix, int target) { if (matrix == null || matrix.length == 0 || matrix[0].length == 0){ return false; } int row = matrix.length; int col = matrix[0].length; int startcol = 0; int startrow = 0; for (int x = 0;x<=col-1;x++){ if (matrix[row-1][x] == target){ return true; }else if (matrix[row-1][x] > target){ break; }else { startcol++; } } for (int x = 0;x<=row-1;x++){ if (matrix[x][col-1] == target){ return true; }else if (matrix[x][col-1] > target){ break; }else { startrow++; } } for (int x = startrow;x<=row-1;x++){ for (int y = startcol;y<=col-1;y++){ if (matrix[x][y] == target){ return true; }else if (matrix[x][y] > target){ break; } } } return false; }
面试题55:跳跃游戏
贪心算法和动态规划都可以解,贪心算法即求最远可到的距离,遍历并更新即可 |
public static boolean canJump(int[] nums) { if (nums == null || nums.length == 0){ return false; } boolean[] cango = new boolean[nums.length]; cango[0] = true; for (int x = 0; x<=nums.length-2;x++){ if (cango[x]){ for (int y = x+1;y<=x+nums[x];y++){ if (y<=nums.length-1){ cango[y] = true; } } }else{ break; } } return cango[nums.length-1]; }
面试题62:不同路径
动态规划,此格存在的解法 = 上面的格子+左边的格子 |
组合数学问题 |
public static int uniquePaths(int m, int n) { if (m<=0 || n<=0){ return 0; } BigInteger index1 = jiecheng(m+n-2); BigInteger index2 = jiecheng(m-1); BigInteger index3 = jiecheng(n-1); return index1.divide(index2.multiply(index3)).intValue(); } public static BigInteger jiecheng(int all){ BigInteger start = new BigInteger("1"); for (int x = 1;x<=all;x++){ start = start.multiply(new BigInteger(String.valueOf(x))); } return start; }
面试题322:零钱兑换
动态规划:d(i) = min{d(i) , d(i- j)+1} |
public static int coinChange(int[] coins, int amount) { if (coins == null || coins.length == 0){ return -1; } if (amount == 0){ return 0; } int[] nums = new int[amount+1]; int min = coins[0]; for (int x :coins){ if (x>amount){ continue; } nums[x] = 1; if (min>x){ min = x; } } if (min>amount){ return -1; } for (int x = min+1;x<=amount;x++){ if (nums[x] == 0) { int sum = Integer.MAX_VALUE; for (int y : coins) { if (x - y >= min && x - y <= amount && nums[x - y] != 0 && nums[x - y] < sum) { sum = nums[x - y] + 1; } } if (sum == Integer.MAX_VALUE){ nums[x] = 0; }else { nums[x] = sum; } } } if (nums[amount] == 0){ return -1; }else { return nums[amount]; } }
面试题300:最长上升子序列
动态规划o(n[2]) , 到i位置的最长子序列为d(i) = maxd(j)+1 当i>j时; |
维护一个数组。不是插入,而是替换 |
public static int lengthOfLIS(int[] nums) { if (nums == null || nums.length == 0){ return 0; } ArrayList<Integer> arrayList = new ArrayList<>(); arrayList.add(nums[0]); for (int x = 0;x<=nums.length-1;x++){ if (nums[x]>arrayList.get(arrayList.size()-1)){ arrayList.add(nums[x]); }else if (nums[x] <= arrayList.get(0)){ arrayList.set(0,nums[x]); }else { int index = 0; while (arrayList.get(index) < nums[x]){ index++; } arrayList.set(index,nums[x]); } } return arrayList.size(); }
面试题297:二叉树的序列化与反序列化
按层次序列化,如果当前为null就不存其子节点了。反序列化时也需要用队列。直接用数组下标的话会因太大而过不了。 |
public static String serialize(TreeNode root) { if (root == null){ return ""; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(root.val); stringBuilder.append(","); ArrayDeque<TreeNode> arrayDeque = new ArrayDeque<>(); arrayDeque.addLast(root); while (arrayDeque.size()!=0){ TreeNode temp = arrayDeque.pollFirst(); if (temp.left!=null){ stringBuilder.append(temp.left.val); stringBuilder.append(","); arrayDeque.addLast(temp.left); }else { stringBuilder.append("#,"); } if (temp.right!=null){ stringBuilder.append(temp.right.val); stringBuilder.append(","); arrayDeque.addLast(temp.right); }else { stringBuilder.append("#,"); } } return stringBuilder.substring(0,stringBuilder.length()-1).toString(); } public static TreeNode deserialize(String data) { if (data == null || data.length() == 0){ return null; } String[] nums = data.split(","); ArrayDeque<TreeNode> arrayDeque = new ArrayDeque<>(); TreeNode root = null; boolean isleft = true; for (String x :nums){ TreeNode current = null; if (!x.equals("#")){ current = new TreeNode(Integer.valueOf(x)); } if (root == null){ root = current; arrayDeque.addLast(root); continue; } TreeNode temp = arrayDeque.peekFirst(); if (isleft){ temp.left = current; if (current!=null){ arrayDeque.addLast(current); } isleft = false; }else { temp.right = current; if (current!=null){ arrayDeque.addLast(current); } isleft =true; arrayDeque.poll(); } } return root; }
面试题380:常数时间插入,删除,获取随机元素
常数时间插入和删除可以用Hash表做到,但获取随机元素则不行,故需要用两个数组结构组合,一个hashmap,存元素及其下标,一个arraylist存元素; |
class RandomizedSet { ArrayList<Integer> arrayList = new ArrayList<>(); HashMap<Integer,Integer> hashMap = new HashMap<>(); /** Initialize your data structure here. */ public RandomizedSet() { } /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */ public boolean insert(int val) { if (hashMap.containsKey(val)){ return false; }else { arrayList.add(val); hashMap.put(val,arrayList.size()-1); return true; } } /** Removes a value from the set. Returns true if the set contained the specified element. */ public boolean remove(int val) { if (!hashMap.containsKey(val)){ return false; }else { int index = hashMap.get(val); int temp = arrayList.get(arrayList.size()-1); arrayList.set(index,temp); arrayList.remove(arrayList.size()-1); hashMap.put(temp,index); hashMap.remove(val); return true; } } /** Get a random element from the set. */ public int getRandom() { if (arrayList.size()-1 >= 0){ Random it = new Random(); int index = it.nextInt(arrayList.size()); return arrayList.get(index); }else { return -1; } } }
面试题202:快乐数
直接无脑加会导致超时,算的时候应该把算过数保留在set里,如果是非快乐数,会出现循环,可以减少很多判断时间 |
public static boolean isHappy(int n) { if (n<=0){ return false; } HashSet<Integer> hashSet = new HashSet<>(); int sum = nextNum(n); while (sum!=-1){ if (sum == 1){ return true; }else { if (hashSet.contains(sum)){ return false; }else { hashSet.add(sum); } sum = nextNum(sum); } } return false; } public static int nextNum(int n){ int sum = 0; String s = String.valueOf(n); for (int x = s.length()-1;x>=0;x--){ int temp = s.charAt(x)-'0'; sum += Math.pow(temp,2); if (sum>= Integer.MAX_VALUE){ return -1; } } return sum; }
面试题172:阶乘后的0
尾数为0为2*5产生,而产生5时肯定已产生多于5的2,故转化为求5的个数,可以用递归求解,也可以分别求出5,25,...的倍数相加 |
public static int trailingZeroes(int n) { if (n<=0){ return 0; } int numof5 = 0; int max = (int)Math.floor(Math.log(n)/Math.log(5)); for (int x = 1;x<=max;x++){ int num = (int)Math.pow(5,x); numof5 += n/num; } return numof5; }
面试题171:excel表序列号
26进制转换为10进制 |
public static int titleToNumber(String s) { if (s == null || s.length() == 0){ return 0; } HashMap<Character,Integer> hashMap = new HashMap<>(); char startchar = 'A'; for (int x = 1;x<=26;x++){ hashMap.put(startchar,x); startchar = (char)(startchar+1); } int sum = 0; for (int x = 0;x<=s.length()-1;x++){ int temp = hashMap.get(s.charAt(x)); int sum_temp = (int)(temp*Math.pow(26,s.length()-1-x)); sum += sum_temp; } return sum; }
面试题50:Pow(x,n)
o(n)的算法:按个数乘,递归会stackoverflow |
o(logn):二分算法 |
常数复杂度:按n中1的个数计算 |
需要特别注意 n为INT_MIN时,-n不是对应的,因为越界了,只能取到INT_MAX,此时还需要乘x;以及x=0时,x为double,判断不能用 ==;
double half = myPow(x,n/2); if (n%2 == 0){ return half*half; }else { return half*half*x; } public static double myPow(double x, int n) { if ( n == 0){ return 1; } if (x < 0.000000001 && x> -0.000000001){ return 0; } if (n<0){ if (n == Integer.MIN_VALUE){ return 1.0/(myPow(x,Integer.MAX_VALUE))*x; } return 1.0/myPow(x,-n); } double half = myPow(x,n/2); if (n%2 == 0){ return half*half; }else { return half*half*x; } }
面试题69:x的平方根
相当于在有序的序列中寻找一个数,故可以用二分进行,要注意数超出整数范围的问题 |
public static int mySqrt(int x) { if (x<0){ return -1; }else if (x==0){ return 0; } int start = 1; int end = x; BigInteger num = new BigInteger(String.valueOf(x)); while (start<=end){ int mid = start+(end-start)/2; BigInteger temp = new BigInteger(String.valueOf(mid)); int index = temp.multiply(temp).compareTo(num); if (index == 0){ return mid; }else if (index == -1){ start = mid+1; }else { end = mid-1; } } return end; }
面试题29:两数相除
用移位运算,尽量每次减去较大的一块,注意当被除数为-MIN,除数为-1时需要返回MAX,为了防止越界,中间计算用long包装一下 |
public static int divide(int dividend, int divisor) { if (divisor == 0){ return -1; } if (dividend == Integer.MIN_VALUE && divisor == -1){ return Integer.MAX_VALUE; } long dend = Math.abs((long)dividend); long dsor = Math.abs((long)divisor); int fuhao = -1; if ((dividend >0 && divisor >0) || (dividend<0 && divisor<0)){ fuhao = 1; } if (dsor == 1){ return (int)(fuhao*dend); } int res = 0; while (dend>=dsor){ long temp = dsor; long p = 1; while (dend >= (temp<<1)){ temp <<= 1; p <<= 1; } res += p; dend -= temp; } return fuhao*res; }
面试题166:分数到小数
直接除出来然后在商里找规律不太容易,采取的是记录下每次的余数,然后比较余数是否出现过,需要注意特殊值0,越界(用long包装) |
public static String fractionToDecimal(int numerator, int denominator) { if (denominator == 0){ return ""; }else if (numerator == 0){ return "0"; } long num = Math.abs((long)numerator); long deno = Math.abs((long)denominator); boolean isneg = (numerator > 0 && denominator < 0) || (numerator<0 && denominator>0); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append((isneg?"-":"")+num/deno); long rem = num%deno; if (rem == 0){ return stringBuilder.toString(); }else { stringBuilder.append('.'); } HashMap<Long,Integer> hashMap = new HashMap<>(); int pos = stringBuilder.indexOf(".")+1; hashMap.put(rem, pos); while (rem!=0){ rem = rem*10; stringBuilder.append(rem/deno); rem = rem%deno; if (hashMap.containsKey(rem)){ int index = hashMap.get(rem); stringBuilder.insert(index,'('); stringBuilder.append(')'); return stringBuilder.toString(); } pos++; hashMap.put(rem,pos); } return stringBuilder.toString(); }
面试题371:两整数之和
用异或算不带进位的和,然后用与操作与移位操作算进位。 |
public static int getSum(int a, int b) { while (a!=0){ int temp = (a&b)<<1; b = a^b; a = temp; } return b; }
面试题150:逆波兰表达式求值
用栈存数字,当遇到操作符,取出两个数,再把计算结果入栈 |
public static int evalRPN(String[] tokens) { if (tokens == null || tokens.length == 0){ return -1; } Stack<Integer> stack = new Stack<>(); for (String x :tokens){ if (x.equals("+") || x.equals("-") || x.equals("*") || x.equals("/")){ int num1 = stack.pop(); int num2 = stack.pop(); if (x.equals("+")){ stack.push(num1+num2); }else if (x.equals("-")){ stack.push(num2-num1); }else if (x.equals("*")){ stack.push(num1*num2); }else { stack.push(num2/num1); } }else { stack.push(Integer.valueOf(x)); } } return stack.pop(); }
面试题169:求众数
可以用hashmap求解,也可以假设第一个数为众数,然后设定计数器,相同+1,不同-1,若计数器为0,更换当前数为众数 |
public static int majorityElement(int[] nums) { if (nums == null || nums.length == 0){ return -1; } HashMap<Integer,Integer> hashMap = new HashMap<>(); for (int x:nums){ if (hashMap.containsKey(x)){ hashMap.put(x,hashMap.get(x)+1); }else { hashMap.put(x,1); } if (hashMap.get(x) > Math.floor(nums.length/2)){ return x; } } return -1; }
面试题621:任务调度器
将任务按个数排序,然后建立大小为n+1的数组,每次从队列中取数,若队列不足,则加上此轮放入数组的次数;否则加上整个数组大小;再遍历数组,将每个任务-1,再放入队列; |
public static int leastInterval(char[] tasks, int n) { if (tasks == null || tasks.length == 0 || n<0){ return 0; } int res = 0; int cycle = n+1; HashMap<Character,Integer> hashMap = new HashMap<>(); for (char x:tasks){ if (hashMap.containsKey(x)){ hashMap.put(x,hashMap.get(x)+1); }else { hashMap.put(x,1); } } PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { if (o1>o2){ return -1; }else if (o1<o2){ return 1; }else { return 0; } } }); for (Map.Entry<Character,Integer> x:hashMap.entrySet()){ priorityQueue.add(x.getValue()); } System.out.print(priorityQueue.toString()); while (priorityQueue.size()!=0){ int cnt = 0; ArrayList<Integer> arrayList = new ArrayList<>(); for (int i = 0;i<cycle;i++){ if (priorityQueue.size()!=0){ arrayList.add(priorityQueue.peek()); priorityQueue.poll(); cnt++; } } for (int x:arrayList){ x--; if (x>0){ priorityQueue.add(x); } } res += priorityQueue.size() == 0 ?cnt:cycle; } return res; }