687. 最长同值路径
class Solution {
int max; //存储最长路径
public int longestUnivaluePath(TreeNode root) {
maxLong(root);
return max;
}
public int maxLong(TreeNode node) {
if(node == null) {
return 0;
}
int left = maxLong(node.left);
int right = maxLong(node.right);
int arrowLeft = 0, arrowRight = 0;
//如果左边节点等于该节点,那么左边单边长度+1,否则就相当于左边断掉
if(node.left != null && node.left.val == node.val) {
arrowLeft = left + 1;
}
if(node.right != null && node.right.val == node.val) {
arrowRight = right + 1;
}
//arrowLeft + arrowRight即为双侧最长长度
max = Math.max(max, arrowLeft + arrowRight);
//返回的是该节点的单侧最长长度
return Math.max(arrowLeft, arrowRight);
}
}
621. 任务调节器
解法一:
class Solution {
public int leastInterval(char[] tasks, int n) {
int[] count = new int[26];
//统计每个任务出现的次数
for(int i = 0; i < tasks.length; i ++) {
count[tasks[i] - 'A'] ++;
}
//排序,count[25]即为次数最多的任务
Arrays.sort(count);
int maxCount = 0; //记录次数最多的任务分别有几个
int i = 25;
while(i >= 0 && count[25] == count[i--]) {
maxCount ++;
}
/*
(count[25]-1)*(n+1)+1:假设A的频率最高,分配任务后每组任务有(n+1)个(n个间隔,1个A)
最后一个A不需要再分配间隔,所以是(count[25]-1)*(n+1)+1
由于可能会出现多个频率相同且都是最高的任务,故需要加上个频率相同且都是最高的任务数
*/
return Math.max((count[25]-1)*(n+1)+maxCount, tasks.length);
}
}
解法二:
class Solution {
public int leastInterval(char[] tasks, int n) {
int[] map = new int[26];
//统计每个任务出现的次数并排序
for (char c: tasks)
map[c - 'A']++;
Arrays.sort(map);
int time = 0;
/*
分配任务,每n+1个任务为一组,每组任务各不相同,每次分完任务重新排序
所以当map[25] == 0时,所有任务都分配完了
优先分配次数最多的,如果没有其它任务用来间隔冷却时间,那么就添加待命状态
*/
while (map[25] > 0) {
int i = 0;
while (i <= n) {
if (map[25] == 0)
break;
if (i < 26 && map[25 - i] > 0)
map[25 - i]--;
time++;
i++;
}
Arrays.sort(map);
}
return time;
}
}
26. 删除排序数组中的重复项
class Solution {
public int removeDuplicates(int[] nums) {
int index = 0;
//双指针,如果不同,就赋值;如果相同就跳过
for(int i = 1; i < nums.length; i ++) {
if(nums[index] != nums[i]) {
index ++;
nums[index] = nums[i];
}
}
return index+1;
}
}
25. K个一组翻转链表
方法一:
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
if(k == 1 || head == null){
return head;
}
//k为一次翻转的节点数,如果要到达一次翻转的最后一个节点,实际上只需要移动k-1次即可
return helper(head,k-1);
}
//递归
public ListNode helper(ListNode head, int k){
if(head == null){
return null;
}
ListNode start = head, end = start;
int index = 0;
//让end移动到第k个节点上
for (; index < k; index ++){
if (end==null) {
break;
}
end = end.next;
}
//不够k个,直接返回head,即不翻转
if(index != k || end == null) {
return head;
}
//记录下一次翻转的起点
ListNode node = end.next;
//将需要翻转的k个节点与后面的连接断开,方便翻转链表
end.next = null;
//翻转,因为每次翻转后链表就与后面的断开了所以需要再连接上
reverse(start);
//连接,翻转后start就是当前链表的尾结点
start.next = helper(node, k);
//end为翻转后链表的头结点
return end;
}
//翻转链表
public void reverse(ListNode head){
ListNode pre = head, next = pre.next;
while(next != null) {
//记录下一个节点
ListNode temp = next.next;
//翻转
next.next = pre;
//后移,准备下一次翻转
pre = next;
next = temp;
}
}
}
方法二:
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
if (k == 1 || head == null)
return head;
return helper(head, k-1);
}
//迭代
public ListNode helper(ListNode head, int k){
//res记录翻转后的头结点用于最后返回
ListNode start = head, res = null;
//pre用于连接
ListNode pre = null;
while (true) {
int index = 0;
ListNode end = start;
for (; index < k; index ++) {
if(end == null) {
break;
}
end = end.next;
}
if(index != k || end == null) {
break;
}
//下一次翻转的起点
ListNode node = end.next;
//断开,方便翻转
end.next = null;
//翻转
reverse(start);
//如果是第一次翻转,那么用res记录翻转后的头结点,即整个链表的头结点,最后需要返回
//如果不是第一次翻转,那么就用pre连接翻转后的头结点(pre记录的是上一次翻转后的尾结点)
if(pre != null){
pre.next = end;
}else {
res = end;
}
//此时已经翻转过了,所以start为翻转后的尾结点
pre = start;
//start移动到下一次翻转的位置
start = node;
}
//剩下的节点不够k个无法反转,与前面翻转后的节点连接起来
if (pre != null)
pre.next = start;
return res;
}
//翻转
public void reverse(ListNode head) {
ListNode pre = head, next = pre.next;
while(next != null) {
//记录下一个节点
ListNode temp = next.next;
//翻转
next.next = pre;
//后移,准备下一次翻转
pre = next;
next = temp;
}
}
}