23. Merge k Sorted Lists
要点:
1. 学会数据结构PriorityQueue(优先队列)的用法, 通过给优先队列传入自定义的经过复写compare方法的比较器实现大根堆或者小根堆。
2. PriorityQueue中不能存放null值,所以每次更新优先队列都需要作判空检查,如遇null值直接剔除。
1 import java.util.Comparator; 2 import java.util.PriorityQueue; 3 4 class Solution { 5 public ListNode mergeKLists(ListNode[] lists) { 6 //要点1 7 PriorityQueue<ListNode> nodesQueue = new PriorityQueue<>(new Comparator<ListNode>() { 8 @Override 9 //将compare方法重写为比较ListNode的val值大小 10 public int compare(ListNode o1, ListNode o2) { 11 return o1.val-o2.val; 12 } 13 }); 14 15 ListNode head = new ListNode(0); 16 for(ListNode node:lists) 17 if(node!=null) 18 nodesQueue.add(node); 19 20 ListNode p = head; 21 while(!nodesQueue.isEmpty()){ 22 //判空检查,如果ListNode的下一个Node是null,则取出该Node后不再将其下一个节点放回优先队列。 23 if(nodesQueue.peek().next==null){ 24 p.next = new ListNode(nodesQueue.poll().val); 25 p = p.next; 26 }else{ 27 ListNode tmp = nodesQueue.poll(); 28 p.next = new ListNode(tmp.val); 29 p = p.next; 30 nodesQueue.add(tmp.next); 31 } 32 } 33 return head.next; 34 } 35 36 }
29. Divide Two Integers
class Solution { //用dividend循环减去diviso并计数减了多少次,这种方法会tle public static int divide(int dividend, int divisor) { //处理两种溢出情况 if(dividend == -2147483648){ if(divisor == 1) return -2147483648; if(divisor == -1) return 2147483647; } /** 32位整数的取值范围是-2147483648~+2147483647 将两个数都转为负数,以处理最大溢出-2147483648 */ //保存符号 int flag = 1; if((dividend>0&&divisor<0)||(dividend<0&&divisor>0)) flag = -1; //都转为负数 dividend = dividend>0?-dividend:dividend; divisor = divisor>0?-divisor:divisor; int res = 0; if(dividend>divisor) return 0; //开始循环取商 while(dividend<0){ int k = 1; //divisor_tmp是变量,只要比dividend小就每次加倍,同时k作为商的计数也加倍 int divisor_tmp = divisor; int tmp=0; while(dividend<divisor_tmp){ tmp = divisor_tmp; //divisor_tmp在加倍的过程中有可能溢出,需要处理 if(divisor_tmp+divisor_tmp>0||divisor_tmp+divisor_tmp==-2147483648) break; divisor_tmp += divisor_tmp; k += k; } //如果跳出加倍循环后,dividend比divisor_tmp大,说明divisor_tmp加倍超过了dividend,需要撤销上一次的加倍 if(dividend>divisor_tmp){ divisor_tmp -= tmp; k>>=1; } //从divideng减去divisor_tmp并保存加倍值 dividend -= divisor_tmp; res += k; } return res*flag; } }
32. Longest Valid Parentheses
连同下面的解释,参考自 https://www.acwing.com/solution/LeetCode/content/114/
算法
(双指针扫描、贪心) O(n)O(n)
假设当前从前到后统计合法括号子串,令(的权值为1,)的权值为-1。首先记录start为某个起点,则在i向后移动的过程中,若当前[start,i]区间和等于0,该字符串是合法的;若区间和大于0,则说明目前缺少右括号,可以不修改start;若区间和小于0,则说明区间已经不合法了,需要修正start为i+1。初始时start从0开始即可。
可是对于…((((合法)(((这种情况,以上算法不能够准确捕捉到最长的合法子串,此时我们逆向考虑,将以上过程反向,从后向前统计,即可处理所有的情况。时间复杂度
两次线性扫描,故时间复杂度为O(n)O(n)。
class Solution { public int longestValidParentheses(String s) { char[] chars = s.toCharArray(); int[] marks = new int[chars.length]; for(int i=0; i<chars.length;i++) marks[i] = chars[i]=='('?1:-1; int pr = 0; int pl = 0; int distance = 0; int tmp = 0; while(pr<marks.length){ tmp+=marks[pr]; if(tmp<0){ tmp = 0; pl = pr+1; } if(tmp == 0) distance = pr-pl+1>distance?pr-pl+1:distance; pr++; } pr = marks.length-1; pl = pr; tmp = 0; while(pl>=0){ tmp += marks[pl] ; if(tmp>0) { tmp = 0; pr = pl-1; } if(tmp == 0) distance = pr-pl+1>distance?pr-pl+1:distance; pl--; } return distance; } }
两道并查集
547. Friend Circles