数据结构-链表 (Java) <三>

承接上文 Java-数据结构-链表<一>

               Java-数据结构-链表<二>

一. 链表简单介绍 

        见 Java-数据结构-链表<一>

二. 链表的代码实现

        见 Java-数据结构-链表<一>

三. leetcode&牛客实例

1-6 见 Java-数据结构-链表<一>

7-13 见Java-数据结构-链表<二>

14. leetcode2 两数相加

        给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。请你将两个数相加,并以相同形式返回一个表示和的链表。你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode dummyhead = new ListNode(0);
        ListNode cur = dummyhead;
        int carry = 0;
        while(l1 != null || l2 != null){
            int L1_val = l1 == null ? 0 : l1.val;
            int L2_val = l2 == null ? 0 : l2.val;
            int sum = L1_val+L2_val+carry;

            carry = sum/10;
            sum = sum%10;

            cur.next = new ListNode(sum);
            cur = cur.next;

            if(l1 != null){
                l1 = l1.next;
            }
            if(l2 != null){
               l2 = l2.next;
            }
        }
        if(carry != 0){
            cur.next = new ListNode(1);
        }
        return dummyhead.next;
    }
}

15. leetcode24 两两相交链表中的节点

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

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

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode pre = new ListNode(0);
        pre.next = head;
        ListNode temp = pre;
        while(temp.next != null && temp.next.next != null) {
            ListNode start = temp.next;
            ListNode end = temp.next.next;
            temp.next = end;
            start.next = end.next;
            end.next = start;
            temp = start;
        }
        return pre.next;
    }
}

16. leetcode23 合并k个升序链表

给你一个链表数组,每个链表都已经按升序排列。请你将所有链表合并到一个升序链表中,返回合并后的链表。

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
  1->4->5,
  1->3->4,
  2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6

暴力

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        List<Integer> list = new ArrayList<>();
        for(int i = 0; i< lists.length; i++){
            ListNode temp = lists[i];
            while(temp != null){
                list.add(temp.val);
                temp = temp.next;
            }
        }
        ListNode head = new ListNode(0); 
        ListNode first = head;
        Collections.sort(list);
        for(int i = 0; i < list.size(); i++){
            first.next = new ListNode(list.get(i));
            first = first.next;
        }
        return head.next;
    }
}

优先队列

class Solution {
    class heap implements Comparator<ListNode>{
        public int compare(ListNode o1, ListNode o2){
            return o1.val - o2.val;
        }
    }
    public ListNode mergeKLists(ListNode[] lists) {
        PriorityQueue<ListNode> list = new PriorityQueue<>(new heap());
        for(ListNode cur : lists){
            while(cur != null){
                list.add(cur);
                cur = cur.next;
            }
        }
        ListNode dummyhead = new ListNode(0);
        ListNode cur = dummyhead;
        while(!list.isEmpty()){
            cur.next = list.poll();
            cur = cur.next;
        }
        cur.next = null;
        return dummyhead.next;
    }
}

两两合并【1】

class Solution {
	public ListNode mergeKLists(ListNode[] lists) {
		if(lists==null || lists.length==0) {
			return null;
		}
		//将lists[0]作为最终合并的链表,然后将list[0]和lists[1]合并成lists[0-1]
		//再将lists[0-1]和lists[2]合并,如此反复最终lists[0]就是最终结果
		ListNode res = lists[0];
		for(int i=1;i<lists.length;i++) {
			res = merge(res,lists[i]);
		}
		return res;
	}
	
	//合并两个有序链表
	private ListNode merge(ListNode a, ListNode b) {
		if(a==null || b==null) {
			return (a==null) ? b : a;
		}
		if(a.val<=b.val) {
			a.next = merge(a.next,b);
			return a;
		} else {
			b.next = merge(a,b.next);
			return b;
		}
	}
}

分治【1】

class Solution {
	public ListNode mergeKLists(ListNode[] lists) {
		if(lists==null || lists.length==0) {
			return null;
		}
		return helper(lists,0,lists.length-1);
	}
	
	//通过mid将数组一分为二,并不断缩小规模,当规模为1时返回并开始合并
	//通过合并两个链表,不断增大其规模,整体看就是不断缩小-最后不断扩大的过程
	private ListNode helper(ListNode[] lists, int begin, int end) {
		if(begin==end) {
			return lists[begin];
		}
		int mid = begin+(end-begin)/2;
		ListNode left = helper(lists,begin,mid);
		ListNode right = helper(lists,mid+1,end);
		return merge(left,right);
	}
	
	//合并两个有序链表
	private ListNode merge(ListNode a, ListNode b) {
		if(a==null || b==null) {
			return (a==null) ? b : a;
		}
		if(a.val<=b.val) {
			a.next = merge(a.next,b);
			return a;
		} else {
			b.next = merge(a,b.next);
			return b;
		}
	}
}

17. leetcode25 k个一组翻转链表

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

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

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

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

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        Deque<ListNode> stack = new ArrayDeque<ListNode>();
        ListNode dummy = new ListNode(0);
        ListNode p = dummy;
        while (true) {
            int count = 0;
            ListNode tmp = head;
            while (tmp != null && count < k) {
                stack.add(tmp);
                tmp = tmp.next;
                count++;
            }
            if (count != k) {
                p.next = head;
                break;
            }
            while (!stack.isEmpty()){
                p.next = stack.pollLast();
                p = p.next;
            }
            p.next = tmp;
            head = tmp;
        }
        return dummy.next;
    }
}

 暴力

public ListNode reverseKGroup(ListNode head, int k) {
    ListNode dummy = new ListNode(0);
    dummy.next = head;

    ListNode pre = dummy;
    ListNode end = dummy;

    while (end.next != null) {
        for (int i = 0; i < k && end != null; i++) end = end.next;
        if (end == null) break;
        ListNode start = pre.next;
        ListNode next = end.next;
        end.next = null;
        pre.next = reverse(start);
        start.next = next;
        pre = start;

        end = pre;
    }
    return dummy.next;
}

private ListNode reverse(ListNode head) {
    ListNode pre = null;
    ListNode curr = head;
    while (curr != null) {
        ListNode next = curr.next;
        curr.next = pre;
        pre = curr;
        curr = next;
    }
    return pre;
}

 

18. leetcode328 奇偶链表

给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。

第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。

请注意,偶数组和奇数组内部的相对顺序应该与输入时保持一致。

你必须在 O(1) 的额外空间复杂度和 O(n) 的时间复杂度下解决这个问题。

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

 O(n) 的额外空间复杂度 再造链表

class Solution {
    public ListNode oddEvenList(ListNode head) {
        if(head == null) return head;
        ListNode dymmyhead = new ListNode(-1);
        ListNode cur = dymmyhead;
        ListNode temp = head;
        while(temp != null && temp.next != null){
            cur.next = new ListNode(temp.val);
            cur = cur.next;
            temp = temp.next.next;
        }
        if(temp != null){
            cur.next = new ListNode(temp.val);
            cur = cur.next;
        } 
        temp = head.next;
        while(temp != null && temp.next != null){
            cur.next = new ListNode(temp.val);
            cur = cur.next;
            temp = temp.next.next;
        }
        if(temp != null) cur.next = new ListNode(temp.val);
        return dymmyhead.next;
    }
}

  O(1) 的额外空间复杂度

class Solution {
    public ListNode oddEvenList(ListNode head) {
        // 分别定义奇偶链表的 虚拟头结点 和 尾结点
        ListNode oddHead = new ListNode();
        ListNode oddTail = oddHead;
        ListNode evenHead = new ListNode();
        ListNode evenTail = evenHead;
        // 遍历原链表,根据 isOdd 标识位决定将当前结点插入到奇链表还是偶链表(尾插法)
        boolean isOdd = true;
        while (head != null) {
            if (isOdd) {
                oddTail.next = head;
                oddTail = oddTail.next;
            } else {
                evenTail.next = head;
                evenTail = evenTail.next;
            }
            head = head.next;
            isOdd = !isOdd;
        }
        // 将奇链表后面拼接上偶链表,并将偶链表的next设置为null
        oddTail.next = evenHead.next;
        evenTail.next = null;
        return oddHead.next;
    }
}

 

 

 

参考自:

【1】leetcode 王尼玛 四种解法+多图演示 23. 合并K个排序链表

【2】leetcode  画手大鹏 画解算法:24. 两两交换链表中的节点

【3】leetcode 房建斌学算法 图解k个一组翻转链表 

【4】leetcode powcai k 个一组翻转链表 

【5】leetcode Sweetiee 🍬 🙋 快来无脑秒懂奇偶链表! 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值