【面试题015】链表中倒数第k个结点 

 

可以用两个指针,当第一个指针指向了第k个时候,第二个指针让他指向链表的第一个元素,然后这两个指针同时向后面移动,

当第一个指针移动到末尾的时候,第二个指针指向的就是倒数第K个结点;两个指针的间距保持为k-1;

当我们遍历列表的时候发现用一个指针是解决不了问题的,我们可以尝试用两个指针来解决问题,

一个指针走的比另外一个指针走得快一点,或者先让其中的一个指针走了若干步,然后再让第二个指针来走;

kth.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
 
#include <iostream>
#include <cstdio>
#include "List.h"

ListNode *FindKthToTail(ListNode *pListHead, unsigned int k)
{
    if(pListHead == NULL || k == 0)
    {
        return NULL;
    }

ListNode *pAhead = pListHead;
    ListNode *pBehind = NULL;

for(unsigned int i = 0; i < k - 1; ++i)
    {
        if(pAhead->m_pNext != NULL)
        {
            pAhead = pAhead->m_pNext;
        }
        else
        {
            return NULL;
        }
    }

pBehind = pListHead;
    while(pAhead->m_pNext != NULL)
    {
        pAhead = pAhead->m_pNext;
        pBehind = pBehind->m_pNext;
    }
    return pBehind;
}

// 测试要找的结点在链表中间
int main()
{
    printf("=====Test1 starts:=====\n");
    ListNode *pNode1 = CreateListNode(1);
    ListNode *pNode2 = CreateListNode(2);
    ListNode *pNode3 = CreateListNode(3);
    ListNode *pNode4 = CreateListNode(4);
    ListNode *pNode5 = CreateListNode(5);

ConnectListNodes(pNode1, pNode2);
    ConnectListNodes(pNode2, pNode3);
    ConnectListNodes(pNode3, pNode4);
    ConnectListNodes(pNode4, pNode5);

printf("expected result: 4.\n");
    ListNode *pNode = FindKthToTail(pNode1, 2);
    PrintListNode(pNode);

DestroyList(pNode1);
    return 0;
}

运行结果:

=====Test1 starts:=====
expected result: 4.
The key in node is 4.
请按任意键继续. . .

List.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
#ifndef _LIST_H_
#define _LIST_H_

struct ListNode
{
    int       m_nValue;
    ListNode *m_pNext;
};

ListNode *CreateListNode(int value);
void ConnectListNodes(ListNode *pCurrent, ListNode *pNext);
void PrintListNode(ListNode *pNode);
void PrintList(ListNode *pHead);
void DestroyList(ListNode *pHead);
void AddToTail(ListNode **pHead, int value);
void RemoveNode(ListNode **pHead, int value);

#endif //_LIST_H_

List.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
 
#include "list.h"
#include <stdio.h>
#include <stdlib.h>

ListNode *CreateListNode(int value)
{
    ListNode *pNode = new ListNode();
    pNode->m_nValue = value;
    pNode->m_pNext = NULL;

return pNode;
}

void ConnectListNodes(ListNode *pCurrent, ListNode *pNext)
{
    if(pCurrent == NULL)
    {
        printf("Error to connect two nodes.\n");
        exit(1);
    }

pCurrent->m_pNext = pNext;
}

void PrintListNode(ListNode *pNode)
{
    if(pNode == NULL)
    {
        printf("The node is NULL\n");
    }
    else
    {
        printf("The key in node is %d.\n", pNode->m_nValue);
    }
}

void PrintList(ListNode *pHead)
{
    printf("PrintList starts.\n");

ListNode *pNode = pHead;
    while(pNode != NULL)
    {
        printf("%d\t", pNode->m_nValue);
        pNode = pNode->m_pNext;
    }

printf("\nPrintList ends.\n");
}

void DestroyList(ListNode *pHead)
{
    ListNode *pNode = pHead;
    while(pNode != NULL)
    {
        pHead = pHead->m_pNext;
        delete pNode;
        pNode = pHead;
    }
}

void AddToTail(ListNode **pHead, int value)
{
    ListNode *pNew = new ListNode();
    pNew->m_nValue = value;
    pNew->m_pNext = NULL;

if(*pHead == NULL)
    {
        *pHead = pNew;
    }
    else
    {
        ListNode *pNode = *pHead;
        while(pNode->m_pNext != NULL)
            pNode = pNode->m_pNext;

pNode->m_pNext = pNew;
    }
}

void RemoveNode(ListNode **pHead, int value)
{
    if(pHead == NULL || *pHead == NULL)
        return;

ListNode *pToBeDeleted = NULL;
    if((*pHead)->m_nValue == value)
    {
        pToBeDeleted = *pHead;
        *pHead = (*pHead)->m_pNext;
    }
    else
    {
        ListNode *pNode = *pHead;
        while(pNode->m_pNext != NULL && pNode->m_pNext->m_nValue != value)
            pNode = pNode->m_pNext;

if(pNode->m_pNext != NULL && pNode->m_pNext->m_nValue == value)
        {
            pToBeDeleted = pNode->m_pNext;
            pNode->m_pNext = pNode->m_pNext->m_pNext;
        }
    }

if(pToBeDeleted != NULL)
    {
        delete pToBeDeleted;
        pToBeDeleted = NULL;
    }
}

Makefile:

1
2
3
4
5
6
7
8
9
10
11
12
 
.PHONY:clean  
CPP=g++  
CFLAGS=-Wall -g  
BIN=test  
OBJS=Kth.o List.o  
LIBS=  
$(BIN):$(OBJS)  
    $(CPP) $(CFLAGS) $^ -o $@ $(LIBS)  
%.o:%.cpp  
    $(CPP) $(CFLAGS) -c $< -o $@  
clean:  
    rm -f *.o $(BIN)  

【面试题015】链表中倒数第k个结点的更多相关文章

  1. 面试题 15:链表中倒数第 k 个结点

    面试题 15:链表中倒数第 k 个结点 题目:输入一个链表,输出该链表中倒数第 k 个结点.为了符合大多数人的习惯, 本题从 1 开始计数,即链表的尾结点是倒数第一个结点.例如一个有 6 个结点的 链 ...

  2. 剑指Offer:面试题15——链表中倒数第k个结点(java实现)

    问题描述 输入一个链表,输出该链表中倒数第k个结点.(尾结点是倒数第一个) 结点定义如下: public class ListNode { int val; ListNode next = null; ...

  3. 剑指offer-面试题15.链表中倒数第k个结点

    题目:输入一个链表,输出该链表的倒数第K个结点.为了符合大多数人的习惯,本题 从1开始计数,即链表的尾结点是倒数第1个节点.例如有一个链表有6个节点,从 头节点开始他们的值依次是1,2,3,4,5,6 ...

  4. 面试题一 链表中倒数第k个结点

    void findLastK(LinkedNode head, int k, int n){ if (head == NULL || k == 0) return; LinkedNode t1 = h ...

  5. 【剑指Offer面试题】 九度OJ1517:链表中倒数第k个结点

    鲁棒性是指程序可以推断输入是否符合规范要求,并对不和要求的输入予以 合理的处理. 题目链接地址: http://ac.jobdu.com/problem.php?pid=1517 题目1517:链表中 ...

  6. 【剑指offer】面试题 22. 链表中倒数第 K 个节点

    面试题 22. 链表中倒数第 K 个节点

  7. (剑指Offer)面试题15:链表中倒数第k个结点

    题目: 输入一个链表,输出该链表中倒数第k个结点. 例如:链表中有6个结点,从头到尾依次为1,2,3,4,5,6,则该链表的倒数第3个结点为4. 链表结点定义: struct ListNode{ in ...

  8. P107、面试题15:链表中倒数第K个结点

    题目:输入一个链表,输出该链表中倒数第K个结点.为了符合大多数人的习惯,本体从1开始奇数,即链表的尾结点是倒数第1个结点.例如一个链表有6个结点,从头结点开始他们的值一次是1.2.3.4.5.6.这个 ...

  9. 面试题15:链表中倒数第K个结点

    输入一个链表,输出该链表中倒数第k个结点. 方法1: 这个解法要循环两次链表 /* public class ListNode { int val; ListNode next = null; Lis ...

随机推荐

  1. AutoEventWireup="false"

    在 Web 服务器控件中,某些事件(通常是 Click 事件)会导致窗体被回发到服务器.HTML 服务器控件和 Web 服务器控件(如 TextBox 控件)中的更改事件将被捕获,但不会立即导致发送. ...

  2. Viewport Resizer下载 谷歌前端自适应开发工具

    原文链接:http://www.phpbiji.cn/article/index/id/107/cid/6.html Viewport Resizer下载 谷歌前端自适应开发工具 在前端开发过程中,随 ...

  3. 如何判断一个js对象是不是Array

    1. instance of 2.constructor 3. isArray 1.var a=new Array(); a instanceof Array; //true 2.var a=new ...

  4. ADO.NET笔记——使用通用数据访问

    相关知识: 前面所有示例,君是访问特定的数据库(SQL Server),因此注入SqlConnection.SqlCommand.SqlDataReader.SqlDataAdapter等类名都添加了 ...

  5. log tag

        Media Player MediaPlayerService     NuPlayerDecoder     NuPlayer      MediaFocusControl       Ac ...

  6. json string 与object 之间的转化

    1.将json string转化成object 1: public static T GetObjectFromJson<T>(string jsonString) 2: { 3: Dat ...

  7. JavaScript中使用console调试程序的坑

    上DEMO a = {key1: [1, 2], 'key2': {'key4': '11'}, 'key3': [1, 2]} console.info(1,a) a.key2.key4 = '22 ...

  8. ActiveMQ.xml文件的主要配置

    ActiveMQ.xml文件默认位置位于 activemq/conf/目录下,主要的配置及解析如下:<beans xmlns="http://www.springframework.o ...

  9. MyEclipse反编译Class文件

    对于需要查看Java Class文件源码的筒子们来说,必须在项目中导入Java源码才能查看Class文件的具体实现,这不仅十分的麻烦,因为有时我们并不可以获得Class文件对应的Java源码.今天就给 ...

  10. vim使用手册

    1. 关于Vim 1.1 Vim的几种模式 2. 启动Vim 3. 文档操作 4. 光标的移动 4.1 基本移动 4.2 翻屏 4.3 标记 5. 插入文本 5.1 基本插入 5.2 改写插入 6. ...