0
点赞
收藏
分享

微信扫一扫

每日一练(day12&PriorityQueue)

小云晓云 2022-01-22 阅读 42

文章目录

「这是我参与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;
    }
}

当然这个显然不是最“优解”,最好的办法其实我们还是可以用到这个栈的。判断回文核心就是判断前面等不等于后面嘛,如果使用栈,那么按顺序存进去,然后再一个一个出栈对比,其实就是相当于反转字符串。但是这样意味着扫描了两遍,第一遍入栈,第二遍对比,但是前面的方式由于是双指针,所以可以对半,第二遍不用那么麻烦。但是这个方法太“简单”不符合我们的身份!所以我们要用到这个栈,没错我又来了负优化了~我们使用递归!

递归

image.png


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()的话显然这做的话,如果数据量极大,那就是作死行为。而且我们是一个数据流,我们数据的长度可能会随时改变,所以我们必须在让这个数据进来的时候就是有序的。

所以在这里我们很自然地就想到了大小堆。

image.png

这不就有序了嘛。那问题了来了如何实现我们的代码,这个时候就要体现我们高级语言的好处了(说句实话让我手写一个我也不行)

我们使用java 里面的 PriorityQueue

PriorityQueue 队列

这个哥们是基于二叉树默小堆
(要注意:默认的PriorityQueue并非保证了整个队列都是有序的,只是保证了队头是最小的)

image.png

那么如果我们要实现大根堆的话我们可以这样。

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;
        }
    }
}
举报

相关推荐

0 条评论