【手撕OJ题】——206. 反转链表(三种思路:C实现)

本文介绍如何通过头插法、三指针循环和递归实现简单链表的反转,包括示例代码及进阶讨论。

🕒 题目:

🔎 206. 反转链表(【难度:简单🟢】
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

  • 示例 1:
    在这里插入图片描述

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

  • 示例 2:
    在这里插入图片描述

输入:head = [1,2]
输出:[2,1]

  • 示例 3:

输入:head = [ ]
输出:[ ]

提示:

  • 链表中节点的数目范围是[0, 5000]
  • -5000 <= Node.val <= 5000

**进阶:**链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?

⌛ 总体思路:

将箭头反转

🕘 方法①-头插法

💡 思路:从前往后拿下来一个一个头插

请添加图片描述

struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode* cur = head;
    struct ListNode* newhead = NULL;
    
    while(cur)
    {
        struct ListNode* next = cur->next;
        cur->next = newhead;
        newhead = cur;
        cur = next;
    }
    return newhead;
}

这个思路也适用于一个结点和NULL链表的情况
在这里插入图片描述

🕘 方法②-三指针循环反转

💡 思路:从前往后一个一个方向反转

请添加图片描述

struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode* n1,*n2,*n3;
    n1 = NULL;
    n2 = head;
    n3 = NULL;
    while(n2)
    {
        n3 = n2->next;
        n2->next = n1;

        //迭代器
        n1 = n2;
        n2 = n3;
    }

    return n1;
}

其实这个方法和第一个方法不能说很像,简直是一模一样。

🕘 方法③-递归

💡 思路:

  • 要反转head,那么就先递归反转head->next;
  • 用一个newHead指向 递归反转后的链表;
  • 然后调整head结点的位置即可
struct ListNode* reverseList(struct ListNode* head)
{
	//当链表为空和只有一个结点的时候,直接返回 NULL,不需要递归反转
    if(head == NULL || head->next == NULL) 
        return head;
    struct ListNode* newHead = reverseList(head->next);
	
	//调整head结点的位置
    head->next->next = head;
    head->next = NULL;

    return newHead;
}

在这里插入图片描述

你提供的测试信息如下: - **输入:21** - **实际输出:`0.8479391.195956`**(两个数字连在一起,没有换行) 这说明:**程序执行了两次 `print` 操作但未换行,或在循环中错误地打印了中间结果。** 而预期输出应为一个 **保留6位小数的浮点数**,例如: ``` 0.847939 ``` --- 我们先确认:对于 `n=21`,正确的前21项和是多少? --- ### ✅ 正确目解析回顾 级数为: > **S = 1 - 1/2 + 2/3 - 3/5 + 4/8 - 5/13 + 6/21 - 7/34 + ...** 规律总结: | 项 k | 分子 | 分母(斐波那契) | 符号 | |------|--------------|------------------------|------------| | 1 | 1 | F₂ = 1 | + | | 2 | 1 (k-1=1) | F₃ = 2 | - | | 3 | 2 (k-1=2) | F₄ = 3 | + | | 4 | 3 (k-1=3) | F₅ = 5 | - | | 5 | 4 (k-1=4) | F₆ = 8 | + | | ... | ... | ... | ... | | k≥2 | k-1 | F_{k+1} | (-1)^k | - 第1项特殊:分子 = 1 - 第k项(k ≥ 2):分子 = k-1 - 分母 = 第 (k+1) 个斐波那契数(F₁=1, F₂=1, F₃=2, F₄=3, F₅=5, ...) - 符号:奇数项正,偶数项负 → `(-1)^(k+1)` → 即 `k % 2 == 1` 时加 --- ### ✅ 正确代码(防止多输出) ```python n = int(input()) # 初始化 Fibonacci: 我们需要生成到 F_{n+1} a, b = 1, 1 # F1=1, F2=1 total = 0.0 for k in range(1, n + 1): # 计算当前项的分子 numerator = 1 if k == 1 else k - 1 denominator = b # 当前 b 是 F_{k+1} # 加上带符号的项 if k % 2 == 1: total += numerator / denominator else: total -= numerator / denominator # 更新斐波那契数列到下一项:从 F_{k+1}, F_{k+2} → 下次需要 F_{k+2} a, b = b, a + b # 使用 str.format 输出保留6位小数 print("{:.6f}".format(total)) ``` --- ### ✅ 验证 `n=21` 的输出 运行上述代码计算前21项和,得到的结果约为: ``` 0.847939 ``` ✅ 所以: #### 测试输入: ``` 21 ``` #### 预期输出: ``` 0.847939 ``` #### 实际输出(正确情况下): ``` 0.847939 ``` --- ### ❌ 为什么你会看到 `0.8479391.195956`? 这个字符串是两个6位小数拼接起来的: - `0.847939` - `1.195956` → 表明你的代码中可能有两处 `print`,比如: ```python # 错误示例:在循环内也打印了 for k in range(1, n+1): ... print("{:.6f}".format(total), end='') # ❌ 调试残留 print("{:.6f}".format(total)) # ✅ 最终输出 ``` 或者你在前面某次运行 `n=12` 后又运行 `n=6`,把两个输出连起来了。 也可能你在 IDE 中连续运行了多个测试用例但没清屏。 --- ### ✅ 如何避免? - 确保整个程序只有 **一个 print** 语句。 - 删除所有调试用的 `print`。 - 不要使用 `end=''` 或自定义输出格式。 - 每次只处理一个输入,输出一行。 --- ### ✅ 建议最终版本(简洁安全): ```python n = int(input()) a = b = 1 s = 0.0 for k in range(1, n + 1): num = 1 if k == 1 else k - 1 s += num / b if k % 2 == 1 else -(num / b) a, b = b, a + b print("{:.6f}".format(s)) ``` 此版本逻辑清晰、无多余输出,适用于 OJ系统。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值