几道高频力扣题


草,老是搞混集合的一些函数,没有IDE的提示举步维艰,特此记录。

stack

Stack<Integer> s1 = new Stack<Integer>();

image-20211125105536196

Queue

  • put()/add()/offer()区别

    • put()

      如果队列满了则会阻塞当前线程,直到队列有空间能够放入为止。

    • add()

      如果入队操作成功则返回true,否则抛出异常。

    • offer()

      入队操作成功返回true,否则返回false。

  • poll()/remove()/take()区别

    • take()

      如果队列为空则会阻塞,直到有元素可以进行出队操作为止。

    • remove()

      如果出队操作失败则抛出异常。

    • poll()

      队列为空则返回null,可以设置等待超时时间。

Deque

Deque<ListNode> queue = new LinkedList<>(); 

isEmpty()

image-20211125105755141

PriorityQueue

PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>(); //小顶堆,默认容量为11
PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(11,new Comparator<Integer>(){ //大顶堆,容量11
    @Override
    public int compare(Integer i1,Integer i2){
        return i2-i1;
    }
});

image-20211125175228659

143. 重排链表(队列,快慢指针,链表翻转)

难度中等708

给定一个单链表 L 的头节点 head ,单链表 L 表示为:

L0 → L1 → … → Ln - 1 → Ln

请将其重新排列后变为:

L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …

不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

img

输入:head = [1,2,3,4]
输出:[1,4,2,3]

示例 2:

img

输入:head = [1,2,3,4,5]
输出:[1,5,2,4,3]

提示:

  • 链表的长度范围为 [1, 5 * 104]
  • 1 <= node.val <= 1000

题解:

一、搞个链表或者双向队列,全部放入,直接模拟操作:

public void reorderList(ListNode head) {
    Deque<ListNode> queue = new LinkedList<>(); 

    ListNode p = head.next;
    while(p!=null) {
        queue.addLast(p);
        p = p.next;
    }

    p = head;
    while(true) {
        if(!queue.isEmpty()) {
            p.next = queue.removeLast();
            p = p.next;
        } else {
            break;
        }
        if(!queue.isEmpty()) {
            p.next = queue.removeFirst();
            p = p.next;
        } else {
            break;
        }
    }
    p.next = null;
}

二、递归处理

image-20211125111227429

三、后半翻转链表,再逐个遍历

快慢指针,翻转链表

1 -> 2 -> 3 -> 4 -> 5 -> 6
第一步,将链表平均分成两半
1 -> 2 -> 3
4 -> 5 -> 6
    
第二步,将第二个链表逆序
1 -> 2 -> 3
6 -> 5 -> 4
    
第三步,依次连接两个链表
1 -> 6 -> 2 -> 5 -> 3 -> 4

代码:

class Solution {
    public void reorderList(ListNode head) {
        if(head==null||head.next==null) return;
        // 快慢指针找中点
        ListNode fast = head.next;
        ListNode slow = head;
        while(fast!=null) {
            if(fast.next == null) {
                break;
            } else {
                fast = fast.next.next;
            }
            slow = slow.next;
        }
        ListNode rightStart = slow.next;
        // System.out.println(rightStart.val);
        rightStart = reverseList(rightStart);
        ListNode fakeHead = new ListNode();
        ListNode p1=head,p2=rightStart;
        while(true) {
            fakeHead.next = p1;
            if(p1==null) return;
            p1 = p1.next;
            fakeHead = fakeHead.next;
            fakeHead.next = p2;
            if(p2==null) return;
            p2 = p2.next;
            fakeHead = fakeHead.next;
        }
    }

    private ListNode reverseList(ListNode head) {
        ListNode cur = head;
        ListNode pre = null;
        ListNode tmp;
        while(cur!=null) {
            tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;
        }
        return pre;
    }
}

69. Sqrt(x)(二分)

给你一个非负整数 x ,计算并返回 x算术平方根

由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。

注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5

示例 1:

输入:x = 4
输出:2

示例 2:

输入:x = 8
输出:2
解释:8 的算术平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。

提示:

  • 0 <= x <= 231 - 1

二分

public int mySqrt(int x) {
    // 一、函数
    // return (int)Math.pow(x,0.5);
    // 二、二分
    long left = 0;
    long right = x;
    long mid;
    do {
        mid = (left+right)/2;
        if(mid*mid==x) return (int)mid;
        if(mid*mid<x) {
            left = mid+1;
            continue;
        } else {
            right = mid-1;
            continue;
        }
    } while(left<=right);
    return (int)(left-1);
}

3. 无重复字符的最长子串(滑窗)

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

示例 4:

输入: s = ""
输出: 0

提示:

  • 0 <= s.length <= 5 * 104
  • s 由英文字母、数字、符号和空格组成

滑窗记录最右边出现的位置,需要看一下。

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int left = 0;
        int maxLen = 0;
        Map<Character,Integer> map = new HashMap<>();
        for(int i=0;i<s.length();i++) {
            if(map.containsKey(s.charAt(i))) {
                left = Math.max(map.get(s.charAt(i))+1,left);
            }
            map.put(s.charAt(i),i);
            maxLen = Math.max(maxLen,i-left+1);
            // System.out.printf("%d %d\n",i,left);
        }
        return maxLen;
    }
}

25. K 个一组翻转链表

难度困难1373

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。

k 是一个正整数,它的值小于或等于链表的长度。

如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

进阶:

  • 你可以设计一个只使用常数额外空间的算法来解决此问题吗?
  • 你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

示例 1:

img

输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]

示例 2:

img

输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]

示例 3:

输入:head = [1,2,3,4,5], k = 1
输出:[1,2,3,4,5]

示例 4:

输入:head = [1], k = 1
输出:[1]

提示:

  • 列表中节点的数量在范围 sz
  • 1 <= sz <= 5000
  • 0 <= Node.val <= 1000
  • 1 <= k <= sz

题解:

比较容易想到的思路还是用一个deque,直接模拟。

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode fakeHead = new ListNode();
        Deque<ListNode> deque = new LinkedList<>();
        ListNode cur = fakeHead;
        while(true) {
            ListNode p = head;
            deque.clear();
            for(int i=0;i<k;i++) {
                if(head==null) {
                    cur.next = p;
                    return fakeHead.next;
                }
                deque.offerLast(head);
                head = head.next;
            }
            while(!deque.isEmpty()) {
                cur.next = deque.pollLast();
                cur = cur.next;
            }
        }
    }
}

或者直接翻转每一组链表:

public ListNode reverseKGroup(ListNode head, int k) {
    ListNode fakeHead = new ListNode();
    fakeHead.next = head;
    ListNode before = fakeHead;
    ListNode after = fakeHead;
    ListNode left = fakeHead;
    ListNode right = fakeHead;
    int i;
    while(true) {
        for(i=0;i<k;i++) {
            right = right.next;
            if(right==null) return fakeHead.next;
        }
        after = right.next;
        left = before.next;
        before.next = reverseList(left,right);
        before = right = left;
    }
}
private ListNode reverseList(ListNode left,ListNode right) {
    ListNode originRight = right;
    right = right.next;
    ListNode cur = left;
    ListNode pre = right;
    ListNode tmp;
    while(pre!=originRight) {
        tmp = cur.next;
        cur.next = pre;
        pre = cur;
        cur = tmp;
    }
    return pre;
}

148. 排序链表

难度中等1381

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表

进阶:

  • 你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?

示例 1:

img

输入:head = [4,2,1,3]
输出:[1,2,3,4]

示例 2:

img

输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]

示例 3:

输入:head = []
输出:[]

提示:

  • 链表中节点的数目在范围 [0, 5 * 104]
  • -105 <= Node.val <= 105

链表快排:

搞三个结点:存放小的,等的,大的,然后接起来。然后再递归小的,大的。

递归归并排序:

class Solution {
    public ListNode sortList(ListNode head) {
        //System.out.printf("%d\n",head.val);
        if(head==null || head.next==null) return head;
        ListNode fast = head.next;
        ListNode slow = head;
        while(fast!=null&&fast.next!=null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        ListNode right = sortList(slow.next);
        slow.next = null;
        ListNode left = sortList(head);
        
        ListNode fakeHead = new ListNode(0);
        ListNode cur = fakeHead;
        while(left!=null&&right!=null) {
            if(left.val>=right.val) {
                cur.next = right;
                right = right.next;
            } else {
                cur.next = left;
                left = left.next;
            }
            cur = cur.next;
        }
        while(left!=null) {
            cur.next = left;
            cur = cur.next;
            left = left.next;
        }
        while(right!=null) {
            cur.next = right;
            cur = cur.next;
            right = right.next;
        }
        return fakeHead.next;
    }
}

自底向上的递归:

直接放弃,一时半会是写不对。

image-20211125172439234

top K问题

排序,局部排序(如冒泡,冒K次),堆,只有k个。QuickSelect,类似快排,但不相关的不管。