牛客刷题日记【链表中倒数最后k个结点|删除链表的倒数第n个节点|两个链表的第一个公共结点】

BM8 链表中倒数最后k个结点

输入一个长度为 n 的链表,设链表中的元素的值为 ai ,返回该链表中倒数第k个节点。

如果该链表长度小于k,请返回一个长度为 0 的链表。

数据范围:0≤n≤1050≤n≤105,0≤ai≤1090≤a**i≤109,0≤k≤1090≤k≤109

要求:空间复杂度 O(n)O(n),时间复杂度 O(n)O(n)

进阶:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)

思考:

设置双指针,让第一个指针先移动k个长度,然后两个指针一起移动。

当第一个指针移动到最后时,第二个指针指的就是目标节点。

代码:

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 *	ListNode(int x) : val(x), next(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pHead ListNode类 
     * @param k int整型 
     * @return ListNode类
     */
    ListNode* FindKthToTail(ListNode* pHead, int k) {
        // write code here

        ListNode* p1 = pHead;
        ListNode* p2 = pHead;

        for (int i = 0;i < k;i++) {
            if (p1 == nullptr) return nullptr;
            p1 = p1->next;
        }
        
        while (p1) {
            p1 = p1->next;
            p2 = p2->next;
        }

        return p2;
    }
};


BM9 删除链表的倒数第n个节点

给定一个链表,删除链表的倒数第 n 个节点并返回链表的头指针
例如,

给出的链表为: 1→2→3→4→51→2→3→4→5, n=2n=2.
删除了链表的倒数第 nn 个节点之后,链表变为1→2→3→51→2→3→5.

数据范围: 链表长度 0≤n≤10000≤n≤1000,链表中任意节点的值满足 0≤val≤1000≤val≤100

要求:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)
备注:

题目保证 nn 一定是有效的

思考:

代码:

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

输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)

数据范围: n≤1000n≤1000
要求:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)

思考:

如果存在公共链表的话,那么一定存在等长的链表。

因此先将长的链表移动指针,至二者等长的区域,在一起遍历,查看是否相同。

代码:

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        ListNode* p1 = pHead1;
		ListNode* p2 = pHead2;

		int len1 = 0, len2 = 0;

		for (;p1;p1 = p1->next)	len1++;
		for (;p2;p2 = p2->next) len2++;

		p1 = pHead1;
		p2 = pHead2;

		// ListNode* res = new ListNode(0);

		if (len1 >= len2) {
			for (int i = 0;i< len1-len2;i++)	p1 = p1->next;
			for (int i = 0;i< len2;i++)
			{
				if (p1 == p2) return p1;
				p1 = p1->next;
				p2 = p2->next;
			}
		}
		else {
			for (int i = 0;i< len2-len1;i++)	p2 = p2->next;
			for (int i = 0;i< len1;i++)
			{
				if (p1 == p2) return p1;
				p1 = p1->next;
				p2 = p2->next;
			}
		}

		return nullptr;
    }
};


BM11 链表相加(二)

假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数。

给定两个这种链表,请生成代表两个整数相加值的结果链表。

数据范围:0≤n,m≤10000000≤n,m≤1000000,链表任意值 0≤val≤90≤val≤9
要求:空间复杂度 O(n)O(n),时间复杂度 O(n)O(n)

思考:

对于两个链表,找到相同长度的子段,二者相加即可

本题难点在于如何进行后续的进位操作,比如:

1-9-3-7 和 6-3

我们选择相同子段,3-7 6-3相加,获得1-9-9-9

使用尾插法得到链表,9-9-9-1

遍历并进位,0-0-0-2

在使用头插法,还原顺序2-0-0-0

代码:

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 *	ListNode(int x) : val(x), next(nullptr) {}
 * };
 */
#include <fstream>
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param head1 ListNode类 
     * @param head2 ListNode类 
     * @return ListNode类
     */
    ListNode* addInList(ListNode* head1, ListNode* head2) {
        // write code here
        ListNode* p1 = head1;
        ListNode* p2 = head2;

        int len1 = 0,len2 = 0;

        for (;p1;p1 = p1->next) len1++;
        for (;p2;p2 = p2->next) len2++;

        p1 = head1;
        p2 = head2;

        ListNode* res = new ListNode(0);

		if (len1 >= len2) {
			for (int i = 0;i< len1-len2;i++)	p1 = p1->next;
			for (int i = 0;i< len2;i++)
			{
				p1->val += p2->val;
				p1 = p1->next;
				p2 = p2->next;
			}
            res->next = head1;
		}
		else {
			for (int i = 0;i< len2-len1;i++)	p2 = p2->next;
			for (int i = 0;i< len1;i++)
			{
				p2->val += p1->val;
				p1 = p1->next;
				p2 = p2->next;
			}
            res->next = head2;
		}       

        ListNode* cur = new ListNode(0);
        ListNode* tt = res->next;

        while (tt) {
            ListNode* tmp = tt;
            tt = tt->next;
            tmp->next = cur->next;
            cur->next = tmp;
        }

        ListNode* dd = cur->next;
        while (dd) {
            if (dd->val >= 10) {
                dd->val %= 10;
                if (dd->next) dd->next->val += 1;
                else {
                    ListNode* tmp = new ListNode(1);
                    dd->next = tmp;
                    tmp->next = nullptr;
                    tmp->val = 1;
                }
            }
            dd = dd->next;
        }

        ListNode* ll = cur->next;
        ListNode* lastRes = new ListNode(0);
        // ListNode* go =lastRes;

        while (ll) {    // 头插法
            ListNode* tmp = ll;
            ll = ll->next;

            tmp->next = lastRes->next;
            lastRes->next = tmp;
        }

        return lastRes->next;

    }
};



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值