Find Longest Unrepeated Letters in Cyclic Linked-List

无聊在版上闲逛发现类似 Cyclic Linked-List的题,自己想了一个试着写一下。

Find Longest Unrepeated Letters Length in Cyclic Linked-List (The List only Contain Upper letter from 'A' - 'Z')

For Example: ...A(head)-B-C-A-B-C-B-D-A(head)..... The Linked-List will start from A and traverse through B,C,A,B,C,B,D and Go back to A.

The Longest Unrepeated Letters Length is 4. (C-B-D-A)


我们可以把这道题分成几部分来进行解答:

1. 如何保存我们遍历到哪些结点的值

2. 如果是不带环的Linked-List,我们怎么找最长不重复子串

3. 如果Linked-List成环,我们需要注意哪些问题


对于第一问,因为题目里结点保存的值为'A' - 'Z', 所以我们可以用一个26位的boolean数组还保存某个值我们是否Visit过

先考虑不带环的Linked-List,我们怎么解决。比较直观的方法就是用两个Pointer,比如 i 和 j,分别指向当前子串的首和尾

1. 我们移动尾字符串,如果此结点的值是不重复的,更新boolean数组相对应位为True,并且将尾指针往后移动

2. 当尾指针遍历到一个值发现重复,首先,这是一个潜在的最大长度,而且说明,在之前我们肯定遍历过相同的值,那么这个值会落在从指针i 到指针 j 之间的位置 (第三点也会保证这一属性)

3. 此时,我们知道重复的字符在i 和 j 之间,那么我们不断移动指针i 去找到这一重复的字符。需要注意的是,在我们找到重复字符之前,首指针跳过的结点对应的字符,我们要给boolean[] 置False, 因为很简单,从i到j的子串中已经不包括i指针刚才跳过的字符了。

4. 当找到重复的字符后,两个指针同时向后移动1个位置,进行下一回的判断

Find Longest Unrepeated Letters in Cyclic Linked-List_第1张图片Find Longest Unrepeated Letters in Cyclic Linked-List_第2张图片Find Longest Unrepeated Letters in Cyclic Linked-List_第3张图片


看上面的3个图,当j指针移动到图2中B的位置的时候,首先从A-B-C是一个潜在的最大长度,其次,我们移动i指针去找之前重复的B,在找B的过程中,我们跳过了A,子串里面不包括A,所以我们要给boolean数组相对应的位置置False. 当我们发现重复的B之后,i 和 j各向后移动一位,继续这个过程。

好,现在我们知道了怎么在无环的Linked-List里面怎么找最大不重复子串,那么如果如图所示,闭环的Linked-List怎么办呢。

我们自然想到什么时候停的问题,如果不带环的Linked-List,只要尾指针移动的队尾就可以了,但是如果有环,如图所示,完全可能出现 C-B-D-A才是最大的不重复子串,换句话说,这回,我们需要首指针移动到队尾才能完成对所有可能的验证(因为最长子串的起始点可能在Linked-List里面任意一个节点)


OK,原理我们明白了,看一下实现这个功能的代码:

public int longestUnrepeat(){
		if (head==null) return 0;
		if (head.next==head) return 1;
		Node i = head;
		Node j = head;
		boolean imove = false;
		boolean[] visit = new boolean[26];
		int maxLen = 0;
		int Len = 0;
		while(true){
			if (i!=head) imove = true;
			if (i==head&&imove) break;
			if (!visit[j.val-'A']){
				visit[j.val-'A'] = true;
				j = j.next;
				Len++;
			}else{
				maxLen = Math.max(maxLen, Len);
				while(i.val!=j.val){
					visit[i.val-'A'] = false;
					i = i.next;
					Len--;
					if (i==head) return maxLen;
				}
				i = i.next;
				j = j.next;
			}
		}
		maxLen = Math.max(maxLen, Len);
		return maxLen;
	}

需要注意的几点:

1. 计算Len的时候,当尾指针j向前移动的时候,Len++,当首指针i向前移动的时候,Len--;

2. 当发现重复的时候,之前的字符子串是一个潜在的最大长度,我们要和之前maxLen进行比较,而当最后退出循环的时候,记得还要和maxLen比较一下当前的长度

3. 当Pointer i 循环完一圈,再次回到Head的时候,跳出循环,那么我们怎么判断它是第二次到达Head的呢? 我用了一个imove boolean变量默认False,当i从Head出发的时候,我们给它置True,说明它确实移动了,再次到达Head的时候便是第二次到达

4. node.val - 'A' 转化为数组index

5. 要小心没有结点,或者一个结点自成环的情况


完整直接能运行的版本请看下面:

public class LoopLinkedList {
	private Node head = null;
	private class Node{
		char val;
		Node next;
		public Node(char c){
			this.val = c;
		}
	}
	public void put(char c){
		if (head==null) head = new Node(c);
		else {
			Node x = head;
			while(x.next!=null) x = x.next;
			x.next = new Node(c);
		}
	}

	public void closeloop(){
		Node x  = head;
		while(x.next!=null)
			x = x.next;
		x.next = head;
	}
	
	public int longestUnrepeat(){
		if (head==null) return 0;
		if (head.next==head) return 1;
		Node i = head;
		Node j = head;
		boolean imove = false;
		boolean[] visit = new boolean[26];
		int maxLen = 0;
		int Len = 0;
		while(true){
			if (i!=head) imove = true;
			if (i==head&&imove) break;
			if (!visit[j.val-'A']){
				visit[j.val-'A'] = true;
				j = j.next;
				Len++;
			}else{
				maxLen = Math.max(maxLen, Len);
				while(i.val!=j.val){
					visit[i.val-'A'] = false;
					i = i.next;
					Len--;
					if (i==head) return maxLen;
				}
				i = i.next;
				j = j.next;
			}
		}
		maxLen = Math.max(maxLen, Len);
		return maxLen;
	}
	
	public static void main(String[] args){
		LoopLinkedList list1 = new LoopLinkedList();
		list1.put('A');
		list1.put('A');
		list1.put('A');
		list1.closeloop();
		int len = list1.longestUnrepeat();
		System.out.println("The Longest Unrepeated Length of Cyclic Linked-List -A-A-A- is ---->" + len);
		LoopLinkedList list2 = new LoopLinkedList();
		list2.put('A');
		list2.put('B');
		list2.put('C');
		list2.put('A');
		list2.put('B');
		list2.put('C');
		list2.put('B');
		list2.put('D');
		list2.closeloop();
		len = list2.longestUnrepeat();
		System.out.println("The Longest Unrepeated Length of Cyclic Linked-List -A-B-C-A-B-C-B-D- is ---->" + len);
	}
}


最后的输出为:

The Longest Unrepeated Length of Cyclic Linked-List -A-A-A- is ---->1

The Longest Unrepeated Length of Cyclic Linked-List -A-B-C-A-B-C-B-D- is ---->4


只测试了几个例子,不知道还有没有别的情况没有考虑充分,欢迎来捉虫 ^_^

你可能感兴趣的:(Find Longest Unrepeated Letters in Cyclic Linked-List)