算法通关村第一关|白银|链表经典问题【持续更新】

1.两个链表第一个公共子节点

1.1 可以考虑将链表元素存储到一个集合里,然后一边遍历第二个链表,一边检测集合中是否存在该结点。本题只需要记录一个结点是否存在,而不需要其他的数据,所以使用 HashSet 。

public ListNode findFirstCommonNodeBySet(ListNode headA, ListNode headB){
	Set<ListNode> set = new HashSet<>();
    while (headA != null) {
        set.add(headA);
        headA = headA.next;
    }

    while (headB != null) {
        if (set.contains(headB))
            return headB;
        headB = headB.next;
    }
    return null;
}

1.2 可以考虑使用栈保存链表的结点,栈底为链表的头结点,栈顶为链表的尾结点,然后比较两个栈的栈顶元素是否相等,如果相等就一起出栈,直到最后一次相等的元素一起出栈,这个元素就是两个链表的第一个公共子结点。

public ListNode findFirstCommonNodeByStack(ListNode headA, ListNode headB){
	Stack<ListNode> stackA = new Stack();
    Stack<ListNode> stackB = new Stack();
    while (headA != null) {
        stackA.push(headA);
        headA = headA.next;
    }
    while (headB != null) {
        stackB.push(headB);
        headB = headB.next;
    }

    ListNode preNode = null;
    while (stackB.size() > 0 && stackA.size() > 0) {
        if (stackA.peek() == stackB.peek()) {
            preNode = stackA.pop();
            stackB.pop();
        } else {
            break;
        }
    }
    return preNode;
}

1.3 将两个链表一前一后拼接在一起,两种拼接方式的长度是一样的,而且两个拼接后的链表最后几位是相同的,也就是说相同的第一位就是公共节点,可以采用双指针。两个指针最终走的长度是相等的。

public ListNode findFirstCommonNode(ListNode pHead1, ListNode pHead2) {
	if (pHead1 == null || pHead2 == null) {
        return null;
    }
    ListNode p1 = pHead1;
    ListNode p2 = pHead2;
    while (p1 != p2) {
        p1 = p1.next;
        p2 = p2.next;
        if (p1 != p2) {
            if (p1 == null) {
                p1 = pHead2;
            }
            if (p2 == null) {
                p2 = pHead1;
            }
        }
    }
    return p1;
}

1.4 用长的链表的长度减去短的链表的长度,得到两个链表的差值。长的链表可以先走这个差值,然后两个链表一起走,就能同时到达公共节点处。

public ListNode findFirstCommonNode(ListNode pHead1, ListNode pHead2){
	if (pHead1 == null || pHead2 == null) {
        return null;
    }
    ListNode current1 = pHead1;
    ListNode current2 = pHead2;
    int l1 = 0, l2 = 0;
    while (current1 != null) {
        current1 = current1.next;
        l1++;
    }
    while (current2 != null) {
        current2 = current2.next;
        l2++;
    }
    current1 = pHead1;
    current2 = pHead2;
    int sub = l1 > l2 ? l1 - l2 : l2 - l1;
    if (l1 > l2) {
        int a = 0;
        while (a < sub) {
            current1 = current1.next;
            a++;
        }
    }
    if (l1 < l2) {
        int a = 0;
        while (a < sub) {
            current2 = current2.next;
            a++;
        }
    }
    while (current2 != current1) {
        current2 = current2.next;
        current1 = current1.next;
    }
    return current1;
}

2.判断链表是否为回文序列

2.1 将链表元素全部压栈,然后一边出栈,一边重新遍历链表。

public boolean isPalindrome(ListNode head){
	ListNode temp = head;
	Stack<Integer> stack = new Stack();
	while (temp != null) {
        stack.push(temp.val);
        temp = temp.next;
    }
	while (head != null) {
        if (head.val != stack.pop()) {
            return false;
        }
        head = head.next;
    }
	return true;
}

2.2 也可以使用集合中的 ArrayList 存储每个 val 值,然后使用 get 方法对前后进行比较。

public boolean isPalindrome(ListNode head) {
	List<Integer> vals = new ArrayList<Integer>();
    ListNode currentNode = head;
    while(currentNode != null){
        vals.add(currentNode.val);
        currentNode = currentNode.next;
    }
    int front = 0;
    int back = vals.size() - 1;
    while(front < back){
        if(vals.get(front) != vals.get(back)){
            return false;
        }
        front++;
        back--;
    }
    return true;
}

3.合并有序链表

4.双指针

5.删除链表元素

如果对您有帮助,请点赞关注支持我,谢谢!❤
如有错误或者不足之处,敬请指正!❤

你可能感兴趣的:(不易,算法通关村,算法,链表,数据结构)