算法基础-链表

1.链表翻转经典代码

public static Node reverseLinkedList(Node head) {
		Node pre = null;
		Node next = null;
		while (head != null) {
			next = head.next;
			head.next = pre;
			pre = head;
			head = next;
		}
		return pre;
	}

	public static DoubleNode reverseDoubleList(DoubleNode head) {
		DoubleNode pre = null;
		DoubleNode next = null;
		while (head != null) {
			next = head.next;
			head.next = pre;
			head.last = next;
			pre = head;
			head = next;
		}
		return pre;
	}


2 题目:K个节点的组内逆序调整

路径:https://leetcode.com/problems/reverse-nodes-in-k-group/

给定一个单链表的头节点head,和一个正数k

实现k个节点的小组内部逆序,如果最后一组不够k个就不调整

例子:

调整前:1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8,k = 3

调整后:3 -> 2 -> 1 -> 6 -> 5 -> 4 -> 7 -> 8

思路:

1.找到从start到第k个的listNode 

2.会start到end的翻转

3循环遍历,每次翻转,把从第二次旋转后的 lastEnd.next = end;

代码实现:

public static class ListNode {
		public int val;
		public ListNode next;
	}

	public static ListNode reverseKGroup(ListNode head, int k) {
		//头给start
		ListNode start = head;
		//从头往后数第K个给end
		ListNode end = getKGroupEnd(start, k);
		//end为空则不需要调整 因为没有够k个
		if (end == null) {
			return head;
		}
		// 第一组凑齐了! 那么end直接给头
		// 因为第一组的逆序后的第一个也就是end 肯定为最后的返回值
		head = end;
		reverse(start, end);
		// 上一组的结尾节点
		ListNode lastEnd = start;
		while (lastEnd.next != null) {
			start = lastEnd.next;
			end = getKGroupEnd(start, k);
			if (end == null) {
				return head;
			}
			reverse(start, end);
			//上一个结尾的下一个指向这次调转后的end 也就是这一组的第一个
			lastEnd.next = end;
			//上一个的结尾的换位这次结尾的
			lastEnd = start;
		}
		return head;
	}

	public static ListNode getKGroupEnd(ListNode start, int k) {
		while (--k != 0 && start != null) {
			start = start.next;
		}
		return start;
	}
	//翻转从s到e
	public static void reverse(ListNode start, ListNode end) {
		//找到e的下一个先
		end = end.next;
		ListNode pre = null;
		ListNode cur = start;
		ListNode next = null;
		while (cur != end) {
			next = cur.next;
			cur.next = pre;
			pre = cur;
			cur = next;
		}
		//翻转过后start 指向下一个需要翻转的start 就是之前赋值的end
		// 但是这个地方不对哈(你需要真正指向的下一个逆序后的第一个值) 后面的循环会赋值对的
		start.next = end;
	}

3题目:链表相加

路径:https://leetcode.com/problems/add-two-numbers/

给定两个链表的头节点head1和head2,
认为从左到右是某个数字从低位到高位,返回相加之后的链表
例子     4 -> 3 -> 6        2 -> 5 -> 3
返回     6 -> 8 -> 9
解释     634 + 352 = 986
 

思路:

1:L长链表S短链表都有 记录加的数和进位   4+2+0(进位)=6 记录6 进位carry0

                                                  3+5+0=8 记录8进位0

                                                6+3+0=9 记录9进位0

2:L有S无   没有

3:LS都无 看进位  没有  

返回986

public static class ListNode {
		public int val;
		public ListNode next;

		public ListNode(int val) {
			this.val = val;
		}

		public ListNode(int val, ListNode next) {
			this.val = val;
			this.next = next;
		}
	}

	public static ListNode addTwoNumbers(ListNode head1, ListNode head2) {
		int len1 = listLength(head1);
		int len2 = listLength(head2);
		//长链表
		ListNode l = len1 >= len2 ? head1 : head2;
		//短链表
		ListNode s = l == head1 ? head2 : head1;
		ListNode curL = l;
		ListNode curS = s;
		ListNode last = curL;
		int carry = 0;
		int curNum = 0;
		//第一个阶段 LS都有  
		while (curS != null) {
			curNum = curL.val + curS.val + carry;
			curL.val = (curNum % 10);
			carry = curNum / 10;
			last = curL;
			curL = curL.next;
			curS = curS.next;
		}
		//第二个阶段 L有  S无
		while (curL != null) {
			curNum = curL.val + carry;
			curL.val = (curNum % 10);
			carry = curNum / 10;
			last = curL;
			curL = curL.next;
		}
		//只有进位
		if (carry != 0) {
			last.next = new ListNode(1);
		}
		return l;
	}

	// 求链表长度
	public static int listLength(ListNode head) {
		int len = 0;
		while (head != null) {
			len++;
			head = head.next;
		}
		return len;
	}

4 链表合并

路径:https://leetcode.com/problems/merge-two-sorted-lists

给定两个有序链表的头节点head1head2

返回合并之后的大链表,要求依然有序

例子     1 -> 3 -> 3 -> 5 -> 7          2 -> 2 -> 3 -> 3-> 7

返回     1 -> 2 -> 2 -> 3 -> 3 -> 3 -> 3 -> 5 -> 7

代码实现:

public static class ListNode {
		public int val;
		public ListNode next;
	}

	public static ListNode mergeTwoLists(ListNode head1, ListNode head2) {
		if (head1 == null || head2 == null) {
			return head1 == null ? head2 : head1;
		}
		ListNode head = head1.val <= head2.val ? head1 : head2;
		ListNode cur1 = head.next;
		ListNode cur2 = head == head1 ? head2 : head1;
		ListNode pre = head;
		while (cur1 != null && cur2 != null) {
			if (cur1.val <= cur2.val) {
				pre.next = cur1;
				cur1 = cur1.next;
			} else {
				pre.next = cur2;
				cur2 = cur2.next;
			}
			pre = pre.next;
		}
		//无论谁不为空,都把之后的给他赋值上就连一块了
		pre.next = cur1 != null ? cur1 : cur2;
		return head;
	}

路径:https://leetcode.com/problems/merge-k-sorted-lists

Input: lists = [[1,4,5],[1,3,4],[2,6]]
Output: [1,1,2,3,4,4,5,6]
Explanation: The linked-lists are:
[
  1->4->5,
  1->3->4,
  2->6
]
merging them into one sorted list:
1->1->2->3->4->4->5->6

思路:利用小根堆实现

代码实现:

public static class ListNode {
		public int val;
		public ListNode next;
	}

	public static class ListNodeComparator implements Comparator<ListNode> {

		@Override
		public int compare(ListNode o1, ListNode o2) {
			return o1.val - o2.val; 
		}

	}

	public static ListNode mergeKLists(ListNode[] lists) {
		if (lists == null) {
			return null;
		}
		//小根堆
		PriorityQueue<ListNode> heap = new PriorityQueue<>(new ListNodeComparator());
		for (int i = 0; i < lists.length; i++) {
			if (lists[i] != null) {
				heap.add(lists[i]);
			}
		}
		if (heap.isEmpty()) {
			return null;
		}
		//先弹出一个作为头好返回
		ListNode head = heap.poll();
		ListNode pre = head;
		//下一个不是空塞回小根堆
		if (pre.next != null) {
			heap.add(pre.next);
		}
		while (!heap.isEmpty()) {
			ListNode cur = heap.poll();
			pre.next = cur;
			pre = cur;
			if (cur.next != null) {
				heap.add(cur.next);
			}
		}
		return head;
	}

一种特殊的单链表节点类描述如下

class Node {

int value;

Node next;

Node rand;

Node(int val) { value = val; }

}

rand指针是单链表节点结构中新增的指针,rand可能指向链表中的任意一个节点,也可能指向null

给定一个由Node节点类型组成的无环单链表的头节点 head,请实现一个函数完成这个链表的复制,并返回复制的新链表的头节点。

要求

时间复杂度O(N),额外空间复杂度O(1) 

https://leetcode.com/problems/copy-list-with-random-pointer/

思路:如果使用map 直接记录node和新建node关系即可,但是不能使用额外空间,我们需要在node.next记录一个新的node,这样就和map一个套路了

public static class Node {
		int val;
		Node next;
		Node random;

		public Node(int val) {
			this.val = val;
			this.next = null;
			this.random = null;
		}
	}


	public static Node copyRandomList(Node head) {
		if (head == null) {
			return null;
		}
		Node cur = head;
		Node next = null;
		// 1 -> 2 -> 3 -> null
		// 1 -> 1' -> 2 -> 2' -> 3 -> 3'
		while (cur != null) {
			next = cur.next;
			cur.next = new Node(cur.val);
			cur.next.next = next;
			cur = next;
		}
		cur = head;
		Node copy = null;
		// 1 1' 2 2' 3 3'
		// 依次设置 1' 2' 3' random指针
		while (cur != null) {
			next = cur.next.next;
			copy = cur.next;
			copy.random = cur.random != null ? cur.random.next : null;
			cur = next;
		}
		Node res = head.next;
		cur = head;
		// 老 新 混在一起,next方向上,random正确
		// next方向上,把新老链表分离
		while (cur != null) {
			next = cur.next.next;
			copy = cur.next;
			cur.next = next;
			copy.next = next != null ? next.next : null;
			cur = next;
		}
		return res;
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

普朗克的朗姆酒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值