每日一练(day12&PriorityQueue)
Posted 'or 1 or 不正经の泡泡
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了每日一练(day12&PriorityQueue)相关的知识,希望对你有一定的参考价值。
文章目录
「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」
题目
每日一练由原来的>=5道题目改>=三道题目,没办法,>=五道题有点多。
第一道先来个简单的
删除链表中的节点
输入: head = [4,5,1,9], node = 5 输出: [4,1,9] 解释: 指定链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9
这个就没啥好说了,嘻嘻~
class Solution
public void deleteNode(ListNode node)
node.val = node.next.val;
node.next = node.next.next;
回文链表
给你一个单链表的头节点
head
,请你判断该链表是否为回文链表。如果是,返回true
;否则,返回false
。
正常解法
这个其实和我们以前做的题目都是一样的。
但是咧现在是在咱们的这个链表里面实现,当然代码也简单。
最简单最直接的思路就是拿到里面的值,然后给一个数组里面然后去判断。
class Solution
public boolean isPalindrome(ListNode head)
List<Integer> temp = new ArrayList<Integer>();
// 将链表的值复制到数组中
ListNode currentNode = head;
while (currentNode != null)
temp.add(currentNode.val);
currentNode = currentNode.next;
// 使用双指针判断是否回文
int front = 0;
int back = temp.size() - 1;
while (front < back)
if (!temp.get(front).equals(temp.get(back)))
return false;
front++;
back--;
return true;
当然这个显然不是最“优解”,最好的办法其实我们还是可以用到这个栈的。判断回文核心就是判断前面等不等于后面嘛,如果使用栈,那么按顺序存进去,然后再一个一个出栈对比,其实就是相当于反转字符串。但是这样意味着扫描了两遍,第一遍入栈,第二遍对比,但是前面的方式由于是双指针,所以可以对半,第二遍不用那么麻烦。但是这个方法太“简单”不符合我们的身份!所以我们要用到这个栈,没错我又来了负优化了~我们使用递归!
递归
class Solution
private ListNode front;
private boolean recursivelyCheck(ListNode currentNode)
if (currentNode != null)
if (!recursivelyCheck(currentNode.next))
return false;
if (currentNode.val != front.val)
return false;
front = front.next;
return true;
public boolean isPalindrome(ListNode head)
front = head;
return recursivelyCheck(head);
叫我优化戴师:
执行耗时:18 ms,击败了5.45% 的Java用户
内存消耗:55.6 MB,击败了7.19% 的Java用户
数据流的中位数
中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
- void addNum(int num) - 从数据流中添加一个整数到数据结构中。
- double findMedian() - 返回目前所有元素的中位数。
名字很呼哨,其实说的东西很简单,所谓中位数不就是有这样一个数,一个数组,一半比它小,一半比他大嘛,同时注意元素奇偶即可。之后是注意到我们这个是数据流,数据流!你要想拿到中位数,你必须保证,你的序列是有序的,这样我就可以保证在O(1)的复杂度拿到中位数。
所以这个题目的问题在于我如何保证,能够让用户输入的数据是一个有序的状态!
如果是加一个数据,我就让它排序一次用Arrary.sort()的话显然这做的话,如果数据量极大,那就是作死行为。而且我们是一个数据流,我们数据的长度可能会随时改变,所以我们必须在让这个数据进来的时候就是有序的。
所以在这里我们很自然地就想到了大小堆。
这不就有序了嘛。那问题了来了如何实现我们的代码,这个时候就要体现我们高级语言的好处了(说句实话让我手写一个我也不行)
我们使用java 里面的 PriorityQueue
PriorityQueue 队列
这个哥们是基于二叉树默小堆
(要注意:默认的PriorityQueue并非保证了整个队列都是有序的,只是保证了队头是最小的)
那么如果我们要实现大根堆的话我们可以这样。
PriorityQueue <Integer> A;
A=new PriorityQueue<>(new Comparator<Integer>()
@Override
public int compare(Integer o1, Integer o2)
// if(o2>o1)
// return 1;
// else
// if(o1==o2)
// return 0;
// else
// return -1;
return o2-o1;
);
这里的话我们直接使用lambda
maxHeap = new PriorityQueue<>((a, b) -> b - a);
class MedianFinder
PriorityQueue<Integer> maxHeap;
PriorityQueue<Integer> minHeap;
public MedianFinder()
maxHeap = new PriorityQueue<>((a, b) -> b - a);
minHeap = new PriorityQueue<>();
public void addNum(int num)
//先比较两个堆顶元素,保证大的数字在小堆,小的在大堆
if (maxHeap.size() == minHeap.size() + 1)
maxHeap.offer(num);
minHeap.offer(maxHeap.poll());
else
minHeap.offer(num);
maxHeap.offer(minHeap.poll());
// 当数据流的元素数量为奇数时,中位数即为大顶堆maxHeap的堆顶元素。
// 当数据流的元素数量为偶数时,中位数为大顶堆maxHeap和小顶堆minHeap堆顶元素的平均数。
public double findMedian()
if (maxHeap.size() > minHeap.size())
return maxHeap.peek();
else
return (maxHeap.peek() + minHeap.peek()) / 2.0;
以上是关于每日一练(day12&PriorityQueue)的主要内容,如果未能解决你的问题,请参考以下文章