/* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
class CCLinkedList{
public static void main
(String[] args
){
// LinkedListExample ex=new LinkedListExample();
// ex.insert(3);
// ex.insert(5);
// ex.insert(8);
// ex.insert(5);
// ex.insert(10);
// ex.insert(2);
// ex.insert(1);
/*
* CC2_1
*/
// ex.traverse();
// System.out.println("==");
// ex.removeDups();
// ex.traverse();
// System.out.println("==");
// ex.removeDupsWithoutBuffer();
// ex.traverse();
/*
* CC2_2
*/
// ex.traverse();
// System.out.println("==");
// Node n=ex.findKthToLast(5);
// System.out.println(n.value);
// ex.traverse();
// System.out.println("==");
// Node k=ex.partition(5);
// while(k.next!=null){
// System.out.println(k.value);
// k=k.next;
// }
// System.out.println(k.value);
LinkedListExample ex1=new LinkedListExample();
ex1.insert(1);
ex1.insert(2);
ex1.insert(3);
ex1.insert(4);
ex1.insert(5);
ex1.insert(6);
ex1.insert(7);
ex1.insert(8);
LinkedListExample ex2=new LinkedListExample();
ex2.insert(8);
// 1->2->3->4->5->6->7->8;
// ^ |
// |___________|
ex1.createCorruptCircular(ex1.head, 4);
System.
out.
println("isCorruptedCircular: "+ex1.
findLoopDetection(ex1.
head));
Node n=ex1.findLoopDetectionNode(ex1.head);
System.
out.
println("LoopStartingNode: "+n.
value);
// ex1.makeIntersection(ex1.head,ex2.head, 4);
// Node n=ex1.findIntersection(ex1.head,ex2.head);
// System.out.println("Intersection node: "+n.value);
// ex2.insert(8);
// Node n=ex2.sumList(ex1.head,ex2.head,0); //backward
// while(n!=null){
// System.out.println(n.value);
// n=n.next;
// }
// Node n=ex2.padding(ex1.head,ex2.head); // forward, padding needed
// while(n!=null){
// System.out.println(n.value);
// n=n.next;
// }
// System.out.println(ex1.isPalindrome(ex1.head));
}
}
class Node<Integer>{
protected Node<Integer> next;
protected int value;
public Node(int value){
this.value=value;
}
}
class LinkedListExample{
public Node head;
public Node findLoopDetectionNode(Node n){
if(n==null) return null;
Node slow=n;
Node fast=n;
while(fast!=null&&fast.next!=null){
slow=slow.next;
fast=fast.next.next;
if(slow==fast) break;
}
if(fast==null || fast.next==null) return null;
slow=n;
while(slow!=fast){
slow=slow.next;
fast=fast.next;
}
return slow;
}
public boolean findLoopDetection(Node n){
if(n==null) return false;
Node slow=n;
Node fast=slow;
while(fast!=null&&fast.next!=null){
slow=slow.next;
fast=fast.next.next;
if(slow==fast) break;
}
if(fast==null || fast.next==null) return false;
return true;
}
public void createCorruptCircular(Node n,int count){
Node tempN=n;
Node tail=getTailNode(tempN);
while(n!=null){
if(count==1){
tail.next=n;
return;
}
count--;
n=n.next;
}
}
public Node getTailNode(Node n){
while(n.next!=null){
n=n.next;
}
return n;
}
public Node findIntersection(Node n1,Node n2){
if(n1==null || n2==null) return null;
//If intersected, two must have the same tail
//tail insepection
if(!sameTail(n1, n2)) return null; // have different tale
//we compare the size, to make the same staring position
int sizeN1=sizeCheck(n1);
int sizeN2=sizeCheck(n2);
int sizeDiff
=Math.
abs(sizeN1
-sizeN2
);
Node longer= sizeN1>=sizeN2 ? n1:n2;
Node shorter= sizeN1>=sizeN2 ? n2:n1;
//we get kth node to make the same starting point between longer and shorter
if(sizeDiff>0) longer = getKthNode(longer, sizeDiff);
//Now we get the same starting point
//move until positioned in the same node
while(longer!=shorter){
longer=longer.next;
shorter=shorter.next;
}
return longer;
}
public Node getKthNode(Node n, int count){
while(count>0){
n=n.next;
count--;
}
return n;
}
public int sizeCheck(Node n){
Node tempN=n;
int size=0;
while(tempN!=null){
size++;
tempN=tempN.next;
}
return size;
}
public boolean sameTail(Node n1, Node n2){
Node tempN1=n1;
Node tempN2=n2;
int tailValueN1=0;
int tailValueN2=0;
while(tempN1!=null){
tailValueN1=tempN1.value;
tempN1=tempN1.next;
}
while(tempN2!=null){
tailValueN2=tempN2.value;
tempN2=tempN2.next;
}
return tailValueN1==tailValueN2?true:false;
}
public void makeIntersection(Node n1, Node n2, int value){
while(n2.next!=null){
n2=n2.next;
}
while(n1!=null){
if(n1.value==value){
n2.next=n1;
return;
}
n1=n1.next;
}
}
/*
* CC2_6
*/
public boolean isPalindrome(Node n){
Node fast=n; // skip two elements
Node slow=n;
Stack<Integer> stack=new Stack<Integer>(); // Important
// when fast=null, slow=N/2
while(fast!=null && fast.next!=null){ // Important
stack.push(slow.value);
slow=slow.next;
fast=fast.next.next;
}
//if odd number fast != null
//if even fast == null
if(fast!=null){
slow=slow.next;
}
while(slow!=null){
int compare=stack.pop();
if(compare!=slow.value)
return false;
slow=slow.next;
}
return true;
}
public void insert(int value){
if(head==null){
head = new Node(value);
}else{
insertNode(head, value);
}
}
/*
* CC2_5_follow_up
*/
public Node padding(Node n1, Node n2){
//first find the size of likedlist
int sizeN1=0;
Node tempN1=n1; // IMPORTANT create temp node and move, because we pass n1, n2 head to other functions
while(tempN1!=null){
sizeN1++;
tempN1=tempN1.next;
}
int sizeN2=0;
Node tempN2=n2;
while(tempN2!=null){
sizeN2++;
tempN2=tempN2.next;
}
if(sizeN1>sizeN2){
n2=addZero(n2,(sizeN1-sizeN2));
}else if(sizeN1<sizeN2){
n1=addZero(n1,(sizeN2-sizeN1));
}
Node currN=sumList2(n1,n2);
return currN;
}
public Node addZero(Node n, int count){
while(count>0){
n=insertHead(n, 0);
count--;
}
return n;
}
public Node insertHead(Node n,int value){
Node newNode=new Node(value);
newNode.next=n;
return newNode;
}
public Node sumList2(Node n1, Node n2){
// 6->1->7
// 2->9->5
// =======
// 6+2=8, save 8
// 1+9=10, save 10
// 7+5=12, save 12
// when linking to each node, we examine if the value >=10, if so, update the previous node value+1;
// Consider all parameters are null
if(n1==null && n2==null) return null;
int result=0;
if(n1!=null){
result += n1.value;
}
if(n2!=null){
result += n2.value;
}
Node currNode=new Node(result);
if(n1.next!=null || n2.next!=null){
Node nextNode = sumList2(n1.next==null?null:n1.next,n2.next==null?null:n2.next);
//nextNode examinization before attached.
if(nextNode.value>=10){
nextNode.value=(nextNode.value%10);
currNode.value=currNode.value+1;
}
currNode.next=nextNode;
}
return currNode;
}
/*
* CC2_5
*/
public Node sumList(Node n1, Node n2, int carry){
// 7->1->6
// 5->9->2
// =======
// 7+5=12, take only second digit 2 and pass the carry to next recursive
// 1+9+1(carry), take only 1, pass 1 carry to next
// 6+2+1(carry), take 9
// return head node 2 that linked to 1 -> 9
// Consider all parameters are null
if(n1==null && n2==null && carry==0) return null;
int result=0;
if(n1!=null){
result += n1.value;
}
if(n2!=null){
result += n2.value;
}
// add carry if exists
result += carry;
// get next carry
int nextCarry=result>=10?1:0;
// we only take second digit
result=result%10;
Node currNode=new Node(result);
Node nextNode = sumList(n1.next==null?null:n1.next,n2.next==null?null:n2.next,nextCarry);
currNode.next=nextNode;
return currNode;
}
public void insertNode(Node n,int value){
while(n.next!=null){
n=n.next;
}
n.next=new Node(value);
}
public void traverse(){
Node temp=head;
while(temp!=null){
System.
out.
println(temp.
value); temp=temp.next;
}
}
public Node findKthToLast(int k){
//O(N^2)
//if we use two loop using runner together
//inside inner loop, count the number of remaining elements to the end
//if the number == k, return the current Node
//O(N)
//use two pointers
//one pointer moves until i<k
//then move two pointer together
//When p1 hits the null, the location of p2 is the kth
Node n1 = head;
Node n2 = head;
for(int i=0;i<k;i++){ // Important
if(n1.next!=null){
n1=n1.next;
}else{
return null; // k is larger than the list length
}
}
while(n1.next!=null){
n1=n1.next;
n2=n2.next;
}
return n2;
}
// O(N^2)
public void removeDupsWithoutBuffer(){
// run two loops
Node current=head;
while(current.next !=null){
int value=current.value;
Node runner=current.next;
Node prevRunner=null;
while(runner.next != null){
if(runner.value==value){
prevRunner.next=runner.next; // Memorize it, Important
}else{
prevRunner=runner; // Memorize it, Important
}
runner=runner.next;
}
current=current.next;
}
}
public void removeDups(){
HashSet<Integer> hash = new HashSet<Integer>();
Node n=head;
Node prev=null; // to remove node, need to save the prev node
while(n.next!=null){
if(hash.contains(n.value)){
prev.next=n.next; //previous node jumps to the current.next node, so the current node deleted
}else{
hash.add(n.value); //HashSet only contains not-duplicated data
prev=n;
}
n=n.next;
}
}
/*
* CC2_4
*/
public Node partition(int pValue){
Node n=head;
Node leftStart=null;
Node leftEnd=null;
Node rightStart=null;
Node rightEnd=null;
while(n!=null){ // listen carefully, loop to the end node
Node next=n.next; // create new one that indicates the next node for the next loop
n.next=null; // we save current Node to the list, make current node's next to blank
if(n.value<pValue){
// update left Linked list
if(leftStart==null){
leftStart=n;
leftEnd=leftStart;
}else{
leftEnd.next=n;
leftEnd=n;
}
}else{
// update right Linked List
if(rightStart==null){
rightStart=n;
rightEnd=rightStart;
}else{
rightEnd.next=n;
rightEnd=n;
}
}
n=next; //return next, NOT n.next
}
//Merge two links
leftEnd.next=rightStart;
return leftStart;
}
/*
* CC2_3
*/
public boolean removeNode(Node n){
if(n==null||n.next==null) return false;
//IMPORTANT
//copy next node data to curret node
//then, link to next.next
Node nextNode=n.next;
n.value=nextNode.value;
n.next=nextNode.next;
return true;
}
public void removeNodeIfValueMatched(int value){
Node temp=head;
while(temp.next!=null){
// in this case, we do not need prevNode, directly, compare next node from current
if(temp.next.value==value){
temp.next=temp.next.next;
System.
out.
println("removed: "+value
); }
temp=temp.next;
}
}
}