算法实现----链表(三)

复制含有随机指针节点的链表

/**题目:复制含有随机指针节点的链表
	 * 
	 **要求:在此Node类中,不仅包含next指针(指向下一个节点),
	 *		还包含一个rand指针(可能指向链表中任意一个节点,包括null)
	 * 	    给定一个该种链表的头节点head,
	 *		请实现一个函数完成这个链表中所有结构的复制,并返回复制的新链表的头节点。
	 * 
	 **进阶问题:不使用额外的数据结构,只用有限的几个变量,
	 * 		    且在时间复杂度为O(n)内完成原问题。
	 */
public class CopyLinkedWithRandom {
	
	public static void main(String[] args) {
		SpecialNode node1 = new SpecialNode(1);
		SpecialNode node2 = new SpecialNode(2);
		SpecialNode node3 = new SpecialNode(3);
		
		node1.next = node2;
		node1.rand = node3;
		node2.next = node3;
		node2.rand = node3;
		node3.next = null;
		node3.rand = null;
		
		SpecialNode copy01 = copyLinkedWithRan01(node1);
		while(copy01 != null) {
			System.out.println(copy01.value+"next:"+(copy01.next== null?"null":copy01.next.value)+"rand:"+(copy01.rand== null?"null":copy01.rand.value));
			copy01 = copy01.next;
		}
		System.out.println("----------");
		SpecialNode copy02 = copyLinkedWithRan02(node1);
		while(copy02 != null) {
			System.out.println(copy02.value+"next:"+(copy02.next== null?"null":copy02.next.value)+"rand:"+(copy02.rand== null?"null":copy02.rand.value));
			copy02 = copy02.next;
		}
	}
	
	//解法一:时间复杂度O(n) 空间复杂度O(n),使用hashMap结构来完成
	public static SpecialNode copyLinkedWithRan01(SpecialNode head) {
		if(head == null) {
			return null;
		}
		HashMap<SpecialNode,SpecialNode> map = new HashMap<SpecialNode,SpecialNode>();
		//遍历链表,存入map中,并创建相同节点
		SpecialNode cur = head;
		while(cur != null) {
			map.put(cur, new SpecialNode(cur.value));
			cur = cur.next;
		}
		//拼接链表
		cur = head;
		while(cur != null) {
			map.get(cur).next = map.get(cur.next);
			map.get(cur).rand = map.get(cur.rand);
			cur = cur.next;
		}
		return map.get(head);
	}
	
	//进阶解法:时间复杂度为O(n),不使用额外的数据结构
	/*思路:在原链表的每一个节点后都copy一个新节点,再遍历一次,为copy的节点添加next和rand指针
	 * 	      最后再将该链表分成两个链表,返回新链表的头节点即可
	 */
	public static SpecialNode copyLinkedWithRan02(SpecialNode head) {
		if(head == null) {
			return null;
		}
		SpecialNode cur = head;
		SpecialNode next = null;
		//遍历copy新节点
		while(cur != null) {
			next = cur.next;
			cur.next = new SpecialNode(cur.value);
			cur.next.next = next;
			cur = next;
		}
		
		//为新节点添加rand指针
		cur = head;
		while(cur != null) {
			//注意空的情况
			cur.next.rand = cur.rand==null?null:cur.rand.next;
			cur = cur.next.next;
		}
		
		//分离两个链表
		cur = head;
		SpecialNode newNode = head.next;
		SpecialNode cur2 = newNode;
		while(cur != null) {
			cur.next = cur.next.next;
			//注意空的情况
			cur2.next = cur.next==null?null:cur.next.next;
			cur = cur.next;
			cur2 = cur2.next;
		}
		
		return newNode;
	}
}
class SpecialNode{
	public SpecialNode next;
	public SpecialNode rand;
	public int value;
	
	public SpecialNode(int value) {
		this.value = value;
	}
}

//方法二:将添加rand指针和分离链表在同一次遍历中处理
private static Node copy2(Node head) {
		Node n1 = head;
		Node n2 = null;
		
		while(n1 != null){
			n2 = n1.next;
			n1.next = new Node(n1.value);
			n1.next.next = n2;
			n1 = n2;
		}
		
		n1 = null;
		n2 = head;
		Node n3 = null;
		
		Node n = head.next;
		int i = 0;
		while(n2 != null){
			if(n2.next == null){
				n2.random = n1.random.next != null? n1.random.next: null;
				n2 = n2.next;
				continue;
			}
			if(i % 2 ==0){
				n3 = n2.next;
				n2.next = n2.next.next;
				n1 = n2;
				n2 = n3;
			}else{
				n2.random = n1.random.next != null? n1.random.next: null;
				n3 = n2.next;
				n2.next = n2.next.next;
				n1 = n2;
				n2 = n3;
			}
			i++;
		}
		return n;

	}

两个单链表生成相加链表

public class AddLinked {
	/**题目:两个单链表生成相加链表
	 * 
	 **要求:假设链表中每一个节点的值都在0-9之间,那么链表整体就可以代表一个整数,
	 *		例如9>3>7  可以代表整数937;
	 *		给定两个这样的链表的头节点head1和head2,
	 *	    请生成代表两个整数相加的结果链表
	 *
	 **例如:链表1为9>3>7,链表2为6>3,最后生成新的结果链表为1>0>0>0
	 * */
	public static void main(String[] args) {
		Node node1 = new Node(9);
		Node node2 = new Node(3);
		Node node3 = new Node(7);
		node1.next = node2;
		node2.next = node3;
		node3.next = null;
		
		Node node4 = new Node(6);
		Node node5 = new Node(3);
		node4.next = node5;
		node5.next = null;
		
//		Node addLinked = addLinked01(node1,node4);
		Node addLinked = addLinked02(node1,node4);
		while(addLinked != null) {
			System.out.println(addLinked.value);
			addLinked = addLinked.next;
		}
		
	}

	// 解法一:利用栈结构求解
	public static Node addLinked01(Node head1, Node head2) {
		Stack<Integer> stack1 = new Stack<Integer>();
		Stack<Integer> stack2 = new Stack<Integer>();
		// 将两个链表中的值分别存入栈中
		while (head1 != null) {
			stack1.push(head1.value);
			head1 = head1.next;
		}
		while (head2 != null) {
			stack2.push(head2.value);
			head2 = head2.next;
		}
		int stack1Value = 0;
		int stack2Value = 0;
		int sum = 0;
		int full = 0;
		Node last = null;
		while (!stack1.isEmpty() || !stack2.isEmpty()) {
			stack1Value = stack1.isEmpty() ? 0 : stack1.pop();
			stack2Value = stack2.isEmpty() ? 0 : stack2.pop();
			sum = stack1Value + stack2Value;
			
			Node cur = new Node((sum + full) % 10);
			cur.next = last;
			last = cur;
			full = (sum + full)/10;
		}
		if(full == 1) {
			Node cur = new Node(1);
			cur.next = last;
			return cur;
		}
		return last;
	}
	
	//解法二:逆序两个链表,然后相加,结束后将两个链表恢复原状,空间复杂度为O(1)
	public static Node addLinked02(Node head1, Node head2) {
		head1 = reverseNode(head1);
		head2 = reverseNode(head2);
		
		int head1Value = 0;
		int head2Value = 0;
		int sum = 0;
		int full = 0;
		Node cur1 = head1;
		Node cur2 = head2;
		Node last = null;
		while(cur1 != null || cur2 != null) {
			head1Value = cur1 == null?0:cur1.value;
			head2Value = cur2 == null?0:cur2.value;
			sum = head1Value + head2Value;
			Node n = new Node((sum + full)%10);
			n.next = last;
			last = n;
			full = (sum + full)/10;
			cur1 = cur1==null?null:cur1.next;
			cur2 = cur2==null?null:cur2.next;
		}
		//如果最后进1,则在最前面添加一个新节点,值为1
		if(full == 1) {
			Node n = new Node(1);
			n.next = last;
			last = n;
		}
		
		//恢复两个链表
		head1 = reverseNode(head1);
		head2 = reverseNode(head2);
		
		return last;
	}
	
	//反转链表
	public static Node reverseNode(Node head) {
		Node pre = null;
		Node next = null;
		while(head != null) {
			next = head.next;
			head.next = pre;
			pre = head;
			head = next;
		}
		return pre;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值