// linked-list, two-pointer
const { LinkedList } = require('../../utils')

/* 
1. Two linked lists are intersecting if they merge at some node. 

  3 --> 1 --> 5 --> 9 
                      --> 7 --> 2 -->  1
              4 --> 6

2. Traverse both lists and get the tail and size. 
3. Check if the tails point to the same node. 
4. If they don't, return null
5. If they do, get the longer and shorter lists
6. Move the longer pointer until it matches the length of the shorter pointer
7. Traverse both lists until both pointers are the same. 

*/

function findIntersection(ll1, ll2) {
	if (!ll1 || !ll2) return null

	const res1 = getTailAndSize(ll1)
	const res2 = getTailAndSize(ll2)

	if (res1.tail !== res2.tail) return null

	let shorter = res1.size < res2.size ? ll1 : ll2
	let longer = res2.size < res2.size ? ll2 : ll1

	let k = Math.abs(res2.size - res1.size)

	while (k > 0 && longer) {
		longer = longer.next
		k--
	}

	while (shorter !== longer) {
		shorter = shorter.next
		longer = longer.next
	}

	return longer

	function getTailAndSize(node) {
		res = { tail: null, size: 0 }
		if (!node) return res

		let len = 1,
			curr = node

		while (curr.next) {
			curr = curr.next
			len++
		}
		return { tail: curr, size: len }
	}
}

/*
n = length of first linked list
m = length of second linked list

Time Complexity - O(n + m)
Space complexity - O(1)
*/

// Tests

const ll1 = new LinkedList()
ll1.fromArray([3, 1, 5, 9, 7, 2, 1])

const ll2 = new LinkedList()
ll2.fromArray([4, 6])

const intersection = ll1.head.next.next.next.next

ll2.head.next.next = intersection

const testCases = [[ll1, ll2, intersection]]

for (const test of testCases) {
	console.log(findIntersection(test[0].head, test[1].head) === test[2])
}