【题解】两个链表的第一个公共结点、链表相加(二)

两个链表的第一个公共结点

题目链接:两个链表的第一个公共结点

解题思路1:利用路程相同

两个指针从两个链表的头结点出发,以相同的速度开始往前走,走完一条继续走另一条,最后一定会相遇,如果有相同节点,那相遇的节点就是第一个公共节点,如果没有相同节点,那相遇的节点就是nullptr,两个指针此时分别指向两条链表的nullptr

代码如下:

    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        ListNode* p1 = pHead1;
		ListNode* p2 = pHead2;
		while(p1 != p2){
			p1 = (p1==nullptr) ? pHead2 : p1->next;
			p2 = (p2==nullptr) ? pHead1 : p2->next;
		}
		return p1;
    }

解题思路2:哈希

将第一个链表的所有节点放到集合中,再遍历第二个链表,查找集合中是否有第二个链表的元素,如果有,则该元素就是两个链表的第一个公共节点

代码如下:

    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
		set<ListNode*> st;
		ListNode* p1 = pHead1;
		ListNode* p2 = pHead2;
		while(p1 != nullptr){
			st.insert(p1);
			p1 = p1->next;
		}
		while(p2 != nullptr){
			if(st.count(p2)){
				return p2;
			}
			p2 = p2->next;
		}
		return nullptr;
	}

解题思路3:从长度入手

首先统计两条链表的长度
接着让较长的链表先走,最后达到两条链表走到最后一样长停下
此时接着以相同的速度往后走,最后两个指针一定会相遇,如果有公共节点,相遇的节点就是公共节点,如果没有公共节点,最后两个节点也会指向相同的nullptr.

代码如下:

	int LengthLink(ListNode* head){
		int length = 0;
		while (head != nullptr) {
			length++;
			head = head->next;
		}
		return length;
	}
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
		int len1 = LengthLink(pHead1);
		int len2 = LengthLink(pHead2);
		while(len1 != len2){
			if(len1 > len2){
				pHead1 = pHead1->next;
				len1--;
			}else{
				pHead2 = pHead2->next;
				len2--;
			}
		}
		while(pHead1 != pHead2){
			pHead1 = pHead1->next;
			pHead2 = pHead2->next;
		}
		return pHead1;
	}

链表相加(二)

题目链接:链表相加(二)

解题思路1:反转链表再相加

代码如下:

    ListNode* Reverse(ListNode* head){
        ListNode* res = nullptr;
        ListNode* pre = res;
        ListNode* cur = head;
        while(cur != nullptr){
            ListNode* pnext = cur->next;
            if(pnext == nullptr) {
                res = cur;
            }
            cur->next = pre;
            pre = cur;
            cur = pnext;
        }
        return res;
    }
    ListNode* addInList(ListNode* head1, ListNode* head2) {
        if(head1 == nullptr) return head2;
        if(head2 == nullptr) return head1;
        //反转两个链表
        ListNode* h1 = Reverse(head1);
        ListNode* h2 = Reverse(head2);
        //添加表头
        ListNode* res = new ListNode(-1);
        ListNode* head = res;
        int carry = 0;//记录进位
        while(h1!=nullptr || h2!=nullptr || carry!=0){
            int v1 = h1==nullptr ? 0 : h1->val;
            int v2 = h2==nullptr ? 0 : h2->val;
            int temp = v1 + v2 + carry;
            carry = temp / 10;//进位可能是1、0
            temp %= 10;
            head->next = new ListNode(temp);
            head = head->next;
            if(h1 != nullptr) 
            h1 = h1->next;
            if(h2 != nullptr) 
            h2 = h2->next;
        }
        return Reverse(res->next);
    }

解题思路2:利用栈

利用栈先进后出的特性来模拟链表的反转,最后每一个得到的值进行头插法得到最终的链表

代码如下:

    ListNode* addInList(ListNode* head1, ListNode* head2) {
        if (head1 == nullptr) return head2;
        if (head2 == nullptr) return head1;
        stack<ListNode*> s1;
        stack<ListNode*> s2;
        ListNode* p1 = head1;
        ListNode* p2 = head2;
        while (p1 != nullptr) {
            s1.push(p1);
            p1 = p1->next;
        }
        while (p2 != nullptr) {
            s2.push(p2);
            p2 = p2->next;
        }
        int carry = 0;//进位
        ListNode* res = nullptr;
        while (!s1.empty() || !s2.empty()) {
            int val = carry;
            if (!s1.empty()) {
                val += s1.top()->val;
                s1.pop();
            }
            if (!s2.empty()) {
                val += s2.top()->val;
                s2.pop();
            }
            carry = val / 10;
            ListNode* cur = new ListNode(val % 10);
            cur->next = res;
            res = cur;
        }
        if(carry > 0){
            ListNode* node = new ListNode(carry);
            node->next = res;
            res = node;
        }
        return res;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值