文章目录
「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」
本博文优先在掘金社区发布!
题目
每日一练由原来的>=5道题目改>=三道题目,没办法,>=五道题有点多。
第一道先来个简单的
删除链表中的节点
这个就没啥好说了,嘻嘻~
class Solution {
public void deleteNode(ListNode node) {
node.val = node.next.val;
node.next = node.next.next;
}
}
回文链表
正常解法
这个其实和我们以前做的题目都是一样的。
但是咧现在是在咱们的这个链表里面实现,当然代码也简单。
最简单最直接的思路就是拿到里面的值,然后给一个数组里面然后去判断。
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用户
数据流的中位数
名字很呼哨,其实说的东西很简单,所谓中位数不就是有这样一个数,一个数组,一半比它小,一半比他大嘛,同时注意元素奇偶即可。之后是注意到我们这个是数据流,数据流!你要想拿到中位数,你必须保证,你的序列是有序的,这样我就可以保证在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;
}
}
}