链表之环形链表

1.判断是否有环

Leetcode 141;easy;

定义两个指针slow和fast,只要slow指针追上每次走两步的fast指针的话就有环,否则就没!

package linkedlist;

public class Main0141环形链表 {
	public static void main(String[] args) {
		
	}
}

class Solution141 {
	public boolean hasCycle(ListNode head) {
		if (head == null || head.next == null)
			return false;
			
		ListNode slow = head;
		ListNode fast = head.next;
		while (slow != fast) {
			if (fast.next == null || fast.next.next == null) {//无环返回false
				return false;
			}
			slow = slow.next;
			fast = fast.next.next;
		}
		return true;
	}
}

class Solution0141 {
	public boolean hasCycle(ListNode head) {
		if (head == null || head.next == null)
			return false;
			
		ListNode p1 = head;
		ListNode p2 = head;
		while (p2 != null && p2.next != null) {
			p1 = p1.next;
			p2 = p2.next.next;
			if (p1 == p2) {
				return true;
			}
		}
		return false;
	}
}

2.返回环形链表的入口结点

Leetcode 142;medium;

分两个阶段。
第一个阶段:定义slow和fast指针,让slow指针追上fast指针,说明有环;
第二个阶段:让slow指针重新指向第一个head结点,然后slow和fast指针相同速度移动,当slow和fast指向同一个节点时,就是环入口结点。

package linkedlist;

public class Main0142环形链表Ⅱ {
	public static void main(String[] args) {
		ListNode head = new ListNode(1);
		ListNode node = new ListNode(2);
		ListNode node1 = new ListNode(3);
		head.next = node;
		node.next = node1;
		node1.next = node;
		ListNode cycle = new Solution142().detectCycle(head);
		System.out.println(cycle.val);
	}
}

class Solution142 {
	public ListNode detectCycle(ListNode head) {
		if (head == null || head.next == null)
			return null;

		ListNode p1 = head;// p1和p2必须都指向头节点
		ListNode p2 = head;
		while (p2.next != null && p2.next.next != null) {
			p1 = p1.next;
			p2 = p2.next.next;
			if (p1 == p2) {
				break;
			}
		}
		if (p2.next == null || p2.next.next == null) {// 无环
			return null;
		}
		p1 = head;
		while (p1 != p2) {// p1=p2时退出循环,即都指向环入口结点
			p1 = p1.next;
			p2 = p2.next;
		}
		return p1;
	}
}

3.约瑟夫环形链表自杀问题

程序员代码面试指南(第2版)

这个问题比较有意思,这个题的大致意思:有n个人,围成一个环,编号1-n,
指定一个k值,从编号1开始,每次报数,当喊到k时,这个人就要自杀,下一个人从1开始,…最后只会剩下一个幸运儿,幸运儿自己选择自己的命运!

此题最后求得的就是哪个人会是“幸运儿”!

下面代码有两种方法求得:法1是按报数每次删除一结点,最后会剩下一个节点;法2利用推导公式会直接求出幸运儿,找到返回即可!

package linkedlist;

public class Main环形单链表的约瑟夫问题 {
	public static void main(String[] args) {
		ListNode head = new ListNode(1);
		ListNode node = new ListNode(2);
		ListNode node1 = new ListNode(3);
		head.next = node;
		node.next = node1;
		node1.next = head;
		ListNode josephus1 = josephus1(head, 2);
		System.out.println(josephus1.val);
		
		int live = getLive(3, 2);
		System.out.println("最后留下的节点:" + live);
	}

	// 每次都删除报数为  m 的节点,最后返回一个节点
	public static ListNode josephus1(ListNode head, int m) {
		if (head == null || head.next == null || m < 1)
			return head;

		ListNode last = head;
		while (last.next != head) {// 走到head前,用于删除
			last = last.next;
		}
		int count = 0;
		while (head != last) {
			count++;
			if (count == m) {
				last.next = head.next;// 删除节点但last指针并未移动
				count = 0;
			} else {
				last = last.next;
			}
			head = last.next;
		}
		return head;
	}
	
	// 公式证明直接返回存活的节点
	public static ListNode josephusKill2(ListNode head, int m) {
		if (head == null || head.next == null || m < 1)
			return head;

		int len = 1;
		ListNode cur = head.next;
		while (cur != head) {
			len++;
			cur = cur.next;
		}
		int live = getLive(len, m);
		while (live != 1) {
			live--;
			head = head.next;
		}
		head.next = head;
		return head;
	}
	
	// 利用链表长度和报数数字计算出存活的节点
	public static int getLive(int len, int m) {
		if (len == 1)
			return 1;
		return (getLive(len - 1, m) + m - 1) % len + 1;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值