数学 整数反转 这个题最简单的思路就是转换为反转字符串然后分析情况,但是实际考虑比较复 杂,另一个思路就是每次得到最后一位,不断从末尾累积得到反转的数,考虑溢 出的情况时要注意溢出条件 这张图是画手大鹏的图,灵魂画手
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Solution { public int reverse (int x) { int ans=0 ; while (x!=0 ) { int pop=x%10 ; if (ans>Integer.MAX_VALUE/10 ||(ans==Integer.MAX_VALUE/10 &&pop>7 )) return 0 ; if (ans<Integer.MIN_VALUE/10 ||(ans==Integer.MIN_VALUE/10 &&pop<-8 )) return 0 ; ans=ans*10 +pop; x=x/10 ; } return ans; } }
回文数 这个题和整数反转很像,不用考虑溢出的情况,如果溢出一定不是回文数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public boolean isPalindrome (int x) { if (x<0 ) return false ; if (x<10 ) return true ; int ans=0 ; int temp=x; while (x!=0 ) { int pop=x%10 ; ans=ans*10 +pop; x=x/10 ; } if (ans==temp) return true ; else return false ; } }
除数博弈 一个叫Asher的分析:如果N是奇数,因为奇数的所有因数都是奇数,因此 N进行一次N-x的操作结果一定是偶数,所以如果a拿到了一个奇数,那么 轮到b的时候,b拿到的肯定是偶数,这个时候b只要进行-1,还给a一个奇 数,那么这样子b就会一直拿到偶数,到最后b一定会拿到最小偶数2,a就 输了,这是一个纯数学问题,最好不要想复杂了
1 2 3 4 5 6 7 8 class Solution { public boolean divisorGame (int N) { if (N%2 ==0 ) return true ; else return false ; } }
2的幂 只需要一直除2就行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution { public boolean isPowerOfTwo (int n) { if (n==1 ) return true ; if (n<=0 ) return false ; while (n%2 ==0 ) { n=n/2 ; if (n==1 ) return true ; } return false ; } }
两数相加 注意进位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 class Solution { public ListNode addTwoNumbers (ListNode l1, ListNode l2) { ListNode node=new ListNode(l1.val+l2.val); ListNode temp=node; boolean flag=false ; if (temp.val>=10 ) { flag=true ; temp.val-=10 ; } l1=l1.next; l2=l2.next; while (l1!=null &&l2!=null ) { temp.next=new ListNode(l1.val+l2.val); if (flag) { temp.next.val++; } if (temp.next.val>=10 ) { flag=true ; temp.next.val-=10 ; } else flag=false ; l1=l1.next; l2=l2.next; temp=temp.next; } if (l1==null &&l2==null ) { if (flag) temp.next=new ListNode(1 ); } while (l1!=null ) { temp.next=new ListNode(l1.val); if (flag) temp.next.val++; if (temp.next.val>=10 ) { temp.next.val-=10 ; } else flag=false ; temp=temp.next; l1=l1.next; } while (l2!=null ) { temp.next=new ListNode(l2.val); if (flag) temp.next.val++; if (temp.next.val>=10 ) { temp.next.val-=10 ; } else flag=false ; temp=temp.next; l2=l2.next; } if (flag) temp.next=new ListNode(1 ); return node; } }
平方数之和 这是一道考数学的题,如果没有相应的数学知识很难巧妙地解出来。根据费马 平方和定理,一个非负整数c能够表示为两个整数的平方和,当且仅当c的形 如4*k+3的质因子的幂次均为偶数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Solution { public boolean judgeSquareSum (int c) { for (int i = 2 ; i * i <= c; i++) { int count = 0 ; if (c % i == 0 ) { while (c % i == 0 ) { count++; c /= i; } if (i % 4 == 3 && count % 2 != 0 ) return false ; } } return c % 4 != 3 ; } }
完美数 这个题最直接的思路就是遍历,但是会超出时间限制,实际上除了1和平方根 之外,正因子都是成对出现的,所以只需要遍历平方根之前的数就行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Solution { public boolean checkPerfectNumber (int num) { if (num == 1 ) { return false ; } int sum = 1 ; int i = 2 ; double sqrt = Math.sqrt(num); for (;i < sqrt;i++) { if (num % i == 0 ) { sum += i; sum += num / i; } } if (i * i == num) { sum += i; } return sum == num; } }
三个数的最大乘积 如果不考虑负数的情况就是num1,如果存在负数的情况就要考虑num2
1 2 3 4 5 6 7 8 class Solution { public int maximumProduct (int [] nums) { Arrays.sort(nums); int num1=nums[nums.length-1 ]*nums[nums.length-2 ]*nums[nums.length-3 ]; int num2=nums[0 ]*nums[1 ]*nums[nums.length-1 ]; return num1>num2?num1:num2; } }
卡牌分组 统计每个数出现的次数,然后求最大公约数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { public boolean hasGroupsSizeX (int [] deck) { int [] count = new int [10000 ]; for (int c: deck) count[c]++; int g = -1 ; for (int i = 0 ; i < 10000 ; ++i) if (count[i] > 0 ) { if (g == -1 ) g = count[i]; else g = gcd(g, count[i]); } return g >= 2 ; } public int gcd (int x, int y) { return x == 0 ? y : gcd(y%x, x); } }
三角形的最大周长 我的代码没有优化,不过思路比较清晰,通过分析可知这三个数一定是连续的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class Solution { public int largestPerimeter (int [] A) { Arrays.sort(A); int a=A[A.length-1 ]; int b=A[A.length-2 ]; int c=A[A.length-3 ]; int i=A.length-3 ; int k=A.length-2 ; int j=A.length-1 ; int num=a+b+c; while (i>=0 ) { if (suit(a,b,c)) return num; else { i--; j--; k--; if (i==-1 ) return 0 ; a=A[i]; b=A[k]; c=A[j]; num=a+b+c; } } return 0 ; } public boolean suit (int a,int b,int c) { if ((a+b>c)&&(a+c>b)&&(b+c>a)) return true ; else return false ; } }
自除数 这道题比较简单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Solution { public List<Integer> selfDividingNumbers (int left, int right) { List<Integer> list=new ArrayList<>(); for (int i=left;i<=right;i++) { if (ischu(i)) list.add(i); } return list; } public boolean ischu (int val) { int temp=val; while (val!=0 ) { int t=val%10 ; if (t==0 ) return false ; if (temp%t!=0 ) return false ; val=val/10 ; } return true ; } }
最大交换 这个题的思路就是从最高位开始找位数最大的进行交换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 class Solution { public int maximumSwap (int num) { int length=0 ; int index=1 ; while (num/index!=0 ) { index*=10 ; length++; } int [] array=new int [length]; int temp=num; int i=0 ; while (num!=0 ) { array[i]=num%10 ; num=num/10 ; i++; } int max=-1 ; int lo=-1 ; for (int k=1 ;k<=length;k++) { max=-1 ; lo=-1 ; for (int j=0 ;j<=length-k;j++) { if (array[j]>max) { max=array[j]; lo=j; } } if (lo!=(length-k)&&(max!=array[length-k])) { int te=array[lo]; array[lo]=array[length-k]; array[length-k]=te; break ; } } index=1 ; int sum=0 ; for (int j=0 ;j<length;j++) { sum=sum+array[j]*index; index*=10 ; } return sum; } }
缺失数字 1 2 3 4 5 6 7 8 9 10 11 class Solution { public int missingNumber (int [] nums) { int length=nums.length; int num=length*(length+1 )/2 ; for (int i=0 ;i<length;i++) { num-=nums[i]; } return num; } }
春招精选50题 https://github.com/frankcbliu/Interview_Notes
二分查找 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 import java.util.*;public class Solution { public int upper_bound_ (int n, int v, int [] a) { if (v<=a[0 ]) return 1 ; if (v>a[n-1 ]) return n+1 ; int index1=0 ; int index2=n-1 ; int mid=(index1+index2)/2 ; while (true ) { if (a[mid]>v) index2=mid-1 ; else if (a[mid]<v) index1=mid+1 ; mid=(index1+index2)/2 ; if (index1>=index2) break ; if (a[mid]==v) break ; } if (a[mid]>=v) { while (a[mid]>=v) mid--; return mid+2 ; } else { while (a[mid]<v) mid++; return mid+1 ; } } }
求平方根 这个题难受的地方是要考虑整数溢出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public int mySqrt (int x) { if (x==0 ) return 0 ; long left=1 ; long right=x/2 ; while (left<right) { long mid=(left+right+1 )/2 ; long value=mid*mid; if (value>x) right=mid-1 ; else left=mid; } return (int )left; } }
滑动窗口的最大值 这道题我好像想简单了,先鸽着
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution { public int [] maxSlidingWindow(int [] nums, int k) { if (nums.length==0 ) return new int []{}; int [] array=new int [nums.length-k+1 ]; for (int i=0 ;i<=nums.length-k;i++) { int max=nums[i]; for (int j=i;j<i+k;j++) max=max>nums[j]?max:nums[j]; array[i]=max; } return array; } }
最长不含重复字符的子字符串 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public int lengthOfLongestSubstring (String s) { int maxlength=0 ; for (int i=0 ;i<s.length();i++) { HashSet<Character> set=new HashSet<>(); int length=0 ; for (int j=i;j<s.length();j++) { if (set.add(s.charAt(j))) length++; else break ; } maxlength=maxlength>length?maxlength:length; } return maxlength; } }
数组中出现超过一半的数 使用hash法,其实也可以不使用。可以使用一个count记录出现的次数,从第一个 数开始依次与下一个数比较,如果相同则count++,不同则count–,如果count 为0则从当前索引重新开始
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution { public int majorityElement (int [] nums) { if (nums.length==1 ) return nums[0 ]; HashMap<String,Integer> map=new HashMap<>(); for (int i=0 ;i<nums.length;i++) { if (map.containsKey(nums[i]+"" )) { int val=map.get(nums[i]+"" ); map.put(nums[i]+"" ,val+1 ); if (val+1 >nums.length/2 ) return nums[i]; } else { map.put(nums[i]+"" ,1 ); } } return 0 ; } }
岛屿的最大面积 利用深度优先搜索
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Solution { public int maxAreaOfIsland (int [][] grid) { if (grid.length==0 ) return 0 ; int max=0 ; for (int i=0 ;i<grid.length;i++) { for (int j=0 ;j<grid[0 ].length;j++) { if (grid[i][j]==1 ) { int num=dfs(i,j,grid); max=max>num?max:num; } } } return max; } public int dfs (int i,int j,int [][] grid) { if (i<0 ||j<0 ||i>=grid.length||j>=grid[0 ].length||grid[i][j]==0 ) return 0 ; int num=1 ; grid[i][j]=0 ; num+=dfs(i-1 ,j,grid); num+=dfs(i+1 ,j,grid); num+=dfs(i,j+1 ,grid); num+=dfs(i,j-1 ,grid); return num; } }
接雨水 这道题的思路很明晰,两个柱子之间包含水,我一开始的思路就是从头开始 遍历一旦找到一个块就计算水,整个块减去黑色的部分就是水
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class Solution { public int trap (int [] height) { int length=height.length; int high=0 ; int width=0 ; int num=0 ; int nnum=0 ; for (int i=0 ;i<length;i++) { if (height[i]==0 &&high==0 ) continue ; else if (height[i]!=0 &&high==0 ) { high=height[i]; width++; nnum+=height[i]; } else { if (height[i]>=high) { num=num+width*high-nnum; nnum=height[i]; width=1 ; high=height[i]; } else { width++; nnum+=height[i]; } } } return num; } }
这个解法是有问题的,我找到块的条件是当前黑色部分的高度大于等于之前 初始的黑色高度就得到一个块,没有考虑就算比初始高度低也能得到块。看 一下大佬的解法
按行求 也就是一行行求水,这个思路就解决了我之前的问题,不需要 考虑更低的部分,对于当前行只要遍历得到更高的黑色就是一个块,这个 块的高度就是1
按列求 对于当前列来说只要找到当前左边最高的墙和右边最高的墙, 如果较矮的墙比当前墙高那么一定有水,否则该列不会有水
动态规划 按列求的时候遍历的每一列都要算出左右的最高列,这样 比较耗时,可以用两个数组分别保存当前列左边和右边的最高列
max_left [i] = Max(max_left [i-1],height[i-1])
max_right[i] = Max(max_right[i+1],height[i+1])
双指针 事实上可以不用两个数组,既然是从左向右遍历的那么左边 这个数组就可以不用,每次遍历的时候就更新到当前左边最大值1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public int trap (int [] height) { int sum = 0 ; int max_left = 0 ; int [] max_right = new int [height.length]; for (int i = height.length - 2 ; i >= 0 ; i--) { max_right[i] = Math.max(max_right[i + 1 ], height[i + 1 ]); } for (int i = 1 ; i < height.length - 1 ; i++) { max_left = Math.max(max_left, height[i - 1 ]); int min = Math.min(max_left, max_right[i]); if (min > height[i]) { sum = sum + (min - height[i]); } } return sum; }
逆序对 一开始都能想到最简单的方法,可惜时间超限。还很容易想到从右往前遍历, 利用一个数组保存当前位置的逆序对,但是不能简单通过相邻两个元素值得 到逆序对,这个思路也不行。优化肯定是想降低时间复杂度,把O(n^2) 降到O(nlogn),大佬提供了一种分治思想,实际上就是利用归并排序 求得所有逆序对,事实上归并排序的过程就是消除所有逆序对的过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 class Solution { public int reversePairs (int [] nums) { if (nums.length==0 ) return 0 ; int [] array=new int [nums.length]; int [] temp=new int [nums.length]; for (int i=0 ;i<nums.length;i++) { temp[i]=nums[i]; } int num=reverse(nums,array,0 ,nums.length-1 ); for (int i=0 ;i<nums.length;i++) { nums[i]=temp[i]; } return num; } public int reverse (int [] nums,int [] array,int left,int right) { if (left==right) return 0 ; int mid=(left+right)/2 ; int numleft=reverse(nums,array,left,mid); int numright=reverse(nums,array,mid+1 ,right); if (nums[mid]<=nums[mid+1 ]) return numleft+numright; int num=merge(nums,array,left,right,mid); return num+numleft+numright; } public int merge (int [] nums,int [] array,int left,int right,int mid) { int count=0 ; int index=0 ; int i=left; int j=mid+1 ; while (i<=mid&&j<=right) { if (nums[i]<=nums[j]) array[index++]=nums[i++]; else { count+=(mid-i+1 ); array[index++]=nums[j++]; } } while (i<=mid) array[index++]=nums[i++]; while (j<=right) array[index++]=nums[j++]; index=0 ; while (left<=right) { nums[left++]=array[index++]; } return count; } }
k个一组反转链表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution { public ListNode reverseKGroup (ListNode head, int k) { ListNode dummy = new ListNode(0 ), prev = dummy, curr = head, next; dummy.next = head; int length = 0 ; while (head != null ) { length++; head = head.next; } head = dummy.next; for (int i = 0 ; i < length / k; i++) { for (int j = 0 ; j < k - 1 ; j++) { next = curr.next; curr.next = next.next; next.next = prev.next; prev.next = next; } prev = curr; curr = prev.next; } return dummy.next; } }
删除排序链表中的重复元素 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution { public ListNode deleteDuplicates (ListNode head) { HashSet<Integer> set=new HashSet<>(); ListNode curr=head; ListNode pre=null ; while (curr!=null ) { if (!set.contains(curr.val)) { set.add(curr.val); pre=curr; } else { pre.next=curr.next; } curr=curr.next; } return head; } }
回文链表 可以使用快慢指针,流程分为5步
找到前半部分链表的尾节点 有两种办法,第一种直接遍历整个链表得 到链表长度,然后再遍历找到中间位置。第二种方式是通过快慢指针获取 链表的中间位置,慢指针每次走一步快指针一次走两步,当快指针到达 末尾时慢指针刚好到终点
反转后半部分链表 之前有一个反转链表的题
判断是否回文
恢复链表
返回结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class Solution { public boolean isPalindrome (ListNode head) { if (head == null ) { return true ; } ListNode firstHalfEnd = endOfFirstHalf(head); ListNode secondHalfStart = reverseList(firstHalfEnd.next); ListNode p1 = head; ListNode p2 = secondHalfStart; boolean result = true ; while (result && p2 != null ) { if (p1.val != p2.val) { result = false ; } p1 = p1.next; p2 = p2.next; } firstHalfEnd.next = reverseList(secondHalfStart); return result; } private ListNode reverseList (ListNode head) { ListNode prev = null ; ListNode curr = head; while (curr != null ) { ListNode nextTemp = curr.next; curr.next = prev; prev = curr; curr = nextTemp; } return prev; } private ListNode endOfFirstHalf (ListNode head) { ListNode fast = head; ListNode slow = head; while (fast.next != null && fast.next.next != null ) { fast = fast.next.next; slow = slow.next; } return slow; } }
复制带随机指针的链表 浅拷贝: 返回地址一样的链表。 深拷贝: 返回地址不一样,但关系一致的链 表。 所以不能直接简单粗暴的遍历复制, 这样出来的复制是一样的地址
二叉树的深度 只使用maxDepth也行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Solution { public int maxDepth (TreeNode root) { if (root==null ) return 0 ; int height=Math.max(height(root.left),height(root.right))+1 ; return height; } public int height (TreeNode node) { if (node==null ) return 0 ; return Math.max(height(node.left),height(node.right))+1 ; } }
从上到下打印二叉树 可以用一个flag判断当前行是从左到右还是从右到左
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Solution { public List<List<Integer>> levelOrder(TreeNode root) { List<List<Integer>> list=new ArrayList<>(); LinkedList<TreeNode> linklist=new LinkedList<>(); int length=0 ; if (root!=null ) linklist.add(root); else return list; length=1 ; boolean flag=true ; while (linklist.size()!=0 ){ ArrayList<Integer> arraylist=new ArrayList<>(); for (int i=length-1 ;i>=0 ;i--){ TreeNode temp=linklist.get(i); arraylist.add(temp.val); if (flag){ if (temp.left!=null ) linklist.add(temp.left); if (temp.right!=null ) linklist.add(temp.right); }else { if (temp.right!=null ) linklist.add(temp.right); if (temp.left!=null ) linklist.add(temp.left); } } list.add(arraylist); int i=0 ; while (i<length) { linklist.poll(); i++; } length=linklist.size(); flag=!flag; } return list; } }
二叉树中第k大的节点 差点忘了中序遍历得到的序列就是有序的,稍微调整一下能够变成逆序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { int n; int res; public int kthLargest (TreeNode root, int k) { n=k; helper(root); return res; } public void helper (TreeNode node) { if (node.right!=null &&n>0 ) helper(node.right); n--; if (n==0 ) { res=node.val; return ; } if (node.left!=null &&n>0 ) helper(node.left); } }
二叉树中和为某一值的路径 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public List<List<Integer>> pathSum(TreeNode root, int sum) { List<List<Integer>> result = new ArrayList<>(); dfs(root, sum, new ArrayList<>(), result); return result; } public void dfs (TreeNode root, int sum, List<Integer> list, List<List<Integer>> result) { if (root == null ) return ; list.add(new Integer(root.val)); if (root.left == null && root.right == null ) { if (sum == root.val) result.add(new ArrayList(list)); list.remove(list.size() - 1 ); return ; } dfs(root.left, sum - root.val, list, result); dfs(root.right, sum - root.val, list, result); list.remove(list.size() - 1 ); }
二叉树的最大路径和 大佬的解法,我还没看懂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Solution { private int maxValue = Integer.MIN_VALUE; public int maxPathSum (TreeNode root) { maxGain(root); return maxValue; } private int maxGain (TreeNode root) { if (root.left == null && root.right == null ){ maxValue = root.val > maxValue ? root.val : maxValue; return root.val; } int leftGain = 0 ; int rightGain = 0 ; if (root.left != null ) leftGain = maxGain(root.left); if (root.right != null ) rightGain = maxGain(root.right); leftGain = Math.max(leftGain, 0 ); rightGain = Math.max(rightGain, 0 ); maxValue = leftGain+rightGain+root.val > maxValue ? leftGain+rightGain +root.val : maxValue; int maxGain = root.val + Math.max(leftGain, rightGain); maxValue = maxGain > maxValue ? maxGain : maxValue; return maxGain; } }
二叉树的右视图 很容易想到层次遍历,但是注意只保留每层最后一个节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Solution { public List<Integer> rightSideView (TreeNode root) { List<TreeNode> list=new LinkedList<TreeNode>(); List<Integer> list2=new LinkedList<>(); TreeNode node=root; if (node==null ) return list2; list.add(root); int temp=0 ; while (!list.isEmpty()) { int num=list.size(); while (num>0 ){ node=list.remove(0 ); if (node.left!=null ) list.add(node.left); if (node.right!=null ) list.add(node.right); num--; temp=node.val; } list2.add(temp); } return list2; } }
最小的k个数 构建小顶堆
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Solution { public int [] getLeastNumbers(int [] arr, int k) { int length=arr.length; for (int i=length/2 -1 ;i>=0 ;i--) { sink(arr,i,length); } int [] array=new int [k]; int index=0 ; for (int i=length-1 ;i>length-1 -k;i--) { array[index++]=arr[0 ]; int temp=arr[i]; arr[i]=arr[0 ]; arr[0 ]=temp; sink(arr,0 ,i); } return array; } public void sink (int [] array,int k,int length) { for (int j=2 *k+1 ;j<length;j=2 *j+1 ) { if (j+1 <length&&array[j]>array[j+1 ]) j++; if (array[j]<array[k]) { int temp=array[k]; array[k]=array[j]; array[j]=temp; k=j; } else { break ; } } } }
两个栈实现队列 直接使用两个Stack,但是栈底的元素无法删除,所以一个添加栈用来添加 元素,当需要删除元素的时候,就把添加栈的元素转移到删除栈中,此时 元素就已经反转顺序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class CQueue { Stack<Integer> stack1,stack2; public CQueue () { stack1 = new Stack<Integer>(); stack2 = new Stack<Integer>(); } public void appendTail (int value) { stack1.push(value); } public int deleteHead () { if (stack1.empty() && stack2.empty()){ return -1 ; } if (stack2.empty()){ while (!stack1.empty()){ stack2.push(stack1.pop()); } } return stack2.pop(); } }
LRU缓存机制 有时间好好研究一下LinkedHashMap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class LRUCache { int capacity; LinkedHashMap<Integer, Integer> cache; public LRUCache (int capacity) { this .capacity = capacity; cache = new LinkedHashMap<Integer, Integer>(capacity, 0.75f , true ) { @Override protected boolean removeEldestEntry (Map.Entry eldest) { return cache.size() > capacity; } }; } public int get (int key) { return cache.getOrDefault(key, -1 ); } public void put (int key, int value) { cache.put(key, value); } }