当前位置:   article > 正文

每日5题Day5 - LeetCode 21 - 25

每日5题Day5 - LeetCode 21 - 25

每一步向前都是向自己的梦想更近一步,坚持不懈,勇往直前!

第一题:21. 合并两个有序链表 - 力扣(LeetCode)

  1. class Solution {
  2. public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
  3. //讨论特殊情况
  4. if (list1 == null) {
  5. return list2;
  6. }
  7. if (list2 == null) {
  8. return list1;
  9. }
  10. //头节点
  11. ListNode node;
  12. if (list1.val <= list2.val) {
  13. node = new ListNode(list1.val);
  14. list1 = list1.next;
  15. } else {
  16. node = new ListNode(list2.val);
  17. list2 = list2.next;
  18. }
  19. //给一个dummy,用来最后定位
  20. ListNode dummy = new ListNode(-1, node);
  21. while (list1 != null || list2 != null) {
  22. //分类讨论
  23. ListNode curnode;
  24. if (list1 != null && list2 != null) {
  25. if (list1.val <= list2.val) {
  26. curnode = new ListNode(list1.val);
  27. list1 = list1.next;
  28. } else {
  29. curnode = new ListNode(list2.val);
  30. list2 = list2.next;
  31. }
  32. }
  33. else{
  34. if(list1 != null){
  35. curnode = new ListNode(list1.val);
  36. list1 = list1.next;
  37. }
  38. else{
  39. curnode = new ListNode(list2.val);
  40. list2 = list2.next;
  41. }
  42. }
  43. node.next = curnode;
  44. node = node.next;
  45. }
  46. return dummy.next;
  47. }
  48. }

上面的代码用了太多的额外空间了,如果考虑使用递归呢?

如果对于链表(树的节点同样如此)使用递归的话,专注于每一个具体节点的行为,我们可以发现当list1为空的时候返回list2,反之亦然,因此这是一个边界情况;否则两者都存在时,当前node的next的next其实应该是返回比较小的那个值(为什么是返回?因为要与上面画横线的地方相对应)我们可以得到:

这样写清爽得多,在子递归中我们也表明了方向。

完整代码如下:

  1. class Solution {
  2. public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
  3. // 如果其中一个链表为空,直接返回另一个链表
  4. if (list1 == null) {
  5. return list2;
  6. }
  7. if (list2 == null) {
  8. return list1;
  9. }
  10. // 递归地选择较小的节点作为合并后的头节点
  11. if (list1.val <= list2.val) {
  12. list1.next = mergeTwoLists(list1.next, list2);
  13. return list1;
  14. } else {
  15. list2.next = mergeTwoLists(list1, list2.next);
  16. return list2;
  17. }
  18. }
  19. }

虽然递归也要使用空间,但至少空间消耗比原来低一些,代码则简单太多了。所以我们对于链表、树节点的处理,尽量要考虑递归。


第二题:22. 括号生成 - 力扣(LeetCode)

  1. class Solution {
  2. List<String> res = new ArrayList<>();
  3. List<Character> path = new ArrayList<>();
  4. public List<String> generateParenthesis(int n) {
  5. int[] flag = new int[2];
  6. traversal(0, n, flag);
  7. return res;
  8. }
  9. private void traversal(int startindex, int n, int[] flag){
  10. if(startindex == n * 2){
  11. StringBuilder sb = new StringBuilder();
  12. for(char ch : path){
  13. sb.append(ch);
  14. }
  15. res.add(sb.toString());
  16. return;
  17. }
  18. if(flag[0] < n){
  19. // 讨论加入左括号的情况
  20. path.add('(');
  21. flag[0]++;
  22. traversal(startindex + 1, n, flag);
  23. flag[0]--;
  24. path.remove(path.size() - 1);
  25. }
  26. if(flag[0] > flag[1]){
  27. //只有在左边括号存在的数量大于右边的时候,
  28. //才可以考虑加入右括号,否则不匹配了
  29. path.add(')');
  30. flag[1]++;
  31. traversal(startindex + 1, n, flag);
  32. flag[1]--;
  33. path.remove(path.size() - 1);
  34. }
  35. }
  36. }

第三题:23. 合并 K 个升序链表 - 力扣(LeetCode)

这道题不好处理,咱们直接考虑使用优先级队列来做,反正是升序,具体过程交给优先级队列来做,我们就负责把所有的值添加进去

  1. /**
  2. * Definition for singly-linked list.
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode() {}
  7. * ListNode(int val) { this.val = val; }
  8. * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
  9. * }
  10. */
  11. class Solution {
  12. ListNode mergeKLists(ListNode[] lists) {
  13. if (lists.length == 0) return null;
  14. // 虚拟头结点
  15. ListNode dummy = new ListNode(-1);
  16. ListNode p = dummy;
  17. // 优先级队列,最小堆
  18. PriorityQueue<ListNode> pq = new PriorityQueue<>(new Comparator<ListNode>(){
  19. @Override
  20. public int compare(ListNode o1, ListNode o2){
  21. return (o1.val) - (o2.val);
  22. }
  23. });
  24. // 将 k 个链表的头结点加入最小堆
  25. for (ListNode head : lists) {
  26. if (head != null)
  27. pq.add(head);
  28. }
  29. while (!pq.isEmpty()) {
  30. // 获取最小节点,接到结果链表中
  31. ListNode node = pq.poll();
  32. p.next = node;
  33. if (node.next != null) {
  34. pq.add(node.next);
  35. }
  36. // p 指针不断前进
  37. p = p.next;
  38. }
  39. return dummy.next;
  40. }
  41. }

第四题:24. 两两交换链表中的节点 - 力扣(LeetCode)

  1. class Solution {
  2. public ListNode swapPairs(ListNode head) {
  3. //特殊情况
  4. if(head == null || head.next == null){
  5. return head;
  6. }
  7. //dummy头节点
  8. ListNode dummyhead = new ListNode(-1, head);
  9. ListNode cur = dummyhead;
  10. //注意这里为什么是判断第二三个节点存在?
  11. while(cur.next != null && cur.next.next != null){
  12. //用变量名指代一下,不然看起来太复杂了
  13. ListNode A = cur.next, B = cur.next.next;
  14. cur.next = B;
  15. A.next = B.next;
  16. B.next = A;
  17. cur = cur.next.next;
  18. }
  19. return dummyhead.next;
  20. }
  21. }


 第五题:25. K 个一组翻转链表 - 力扣(LeetCode)

  1. class Solution {
  2. public ListNode reverseKGroup(ListNode head, int k) {
  3. if (head == null || head.next == null) {
  4. return head;
  5. }
  6. ListNode tail = head;
  7. for (int i = 0; i < k; i++) {
  8. //剩余数量小于k的话,则不需要反转。
  9. if (tail == null) {
  10. return head;
  11. }
  12. tail = tail.next;
  13. }
  14. // 反转前 k 个元素
  15. ListNode newHead = reverse(head, tail);
  16. //下一轮的开始的地方就是tail
  17. head.next = reverseKGroup(tail, k);
  18. return newHead;
  19. }
  20. // 左闭右开区间
  21. private ListNode reverse(ListNode head, ListNode tail) {
  22. ListNode pre = null;
  23. ListNode next = null;
  24. while (head != tail) {
  25. next = head.next;
  26. head.next = pre;
  27. pre = head;
  28. head = next;
  29. }
  30. return pre;
  31. }
  32. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/615485
推荐阅读
相关标签
  

闽ICP备14008679号