反转链表和查找倒数第K个节点

11 篇文章 0 订阅

一:链表的逆置(反转链表)
题目:定义一个函数,输入一个链表的头结点,反转该链表并输出反转后的头结点:
节点的结构

struct ListNode
{

    ListNode(const int& val)
    :_val(val)
    ,next(NULL)
    {}
    int _val;
    ListNode*next;
};

这里写图片描述

这里面我们需要三个指针分别是cur,用来顺序遍历整个链表,newhead指针用来保存逆置的头结点,prev用来逆序遍历链表.
步骤:
1:先遍历整个链表找到当前节点的下一个节点为空,即为尾节点也是逆置后的头结点
2:prev用来保存当前节点的上一个节点.
3:然后更新节点的位置,把当前节点指针指向前一个节点,再把它的下一个指针指向当前位置,这样就可以保证所有节点链在一起了.

ListNode*ReverseList(ListNode*phead)
{
  ListNode *cur =phead;
  ListNode*newhead=NULL;
   ListNode*prev =NULL;
    while(cur!=NULL)
    {

        ListNode*_next = cur->next;
        if(_next ==NULL)

        newhead =cur;//找到逆置后的头结点

        cur->next =prev;//保存上一个节点
      //更新当前节点的位置
        prev = cur;
        cur =_next;
    }
    return newhead;
}

二:查找倒数第k个节点
题目:输入一个链表,数除该链表的倒数第K个节点.
常规的思路是从尾到头开始遍历,然后就可以找到第k个节点,但是我们忽略了一个前提的条件就是这个链表时单向链表,不能从后先前遍历,因此这种方法行不通

既然从尾到头不能遍历我们还是从头遍历,那么如何找到倒数第k个节点呢?我们先假设链表有n个节点,那么倒数第K个节点就是从开始向后走n-k+1(n>k)步就好了,如何得到节点数n,遍历链表每遍历一个,计数器加1;
查找倒数第K个节点我们就要遍历遍历两次事件复杂度就是N^2,那么如何只遍历一次事件复杂度是0(N)呢?
方法:快慢指针
这里写图片描述
我们仔细分析下,
第一步:开始的时候假设快慢指针都指向首位置,
第二步:让快指针先走k-1步,慢指针不动,
第三步:快慢指针同时走,当快指针走两步的之后刚好到达链表的尾,而,慢指针走两步刚好到达K(值为3)的位置.
这样就可以实现查找倒数第k个目的.

ListNode *FindKthToTail(ListNode*phead,unsigned int k)
{
//首先要判断头结点是否为空,以及k是否有效
    if(phead ==NULL||k ==0)
    return NULL;
    ListNode*fast=phead;
    ListNode*slow =phead;

    for(unsigned i =0;i<k-1;i++)
    {
   //满足k小于结点的总数
        if(fast->next ==NULL)
        {
            return NULL;
        }
        else{
      fast =fast->next;
       }
    }
    while(fast->next!=NULL)
    {
        fast =fast->next;
        slow =slow->next;
    }
    return slow;
}

三:验证:(C++实现)

#include<iostream>
#include<stdlib.h>
using namespace std;
struct ListNode
{

    ListNode(const int& val)
    :_val(val)
    ,next(NULL)
    {}
    int _val;
    ListNode*next;
};
//逆置单链表
ListNode*ReverseList(ListNode*phead)
{
  ListNode *cur =phead;
  ListNode*newhead=NULL;
   ListNode*prev =NULL;
    while(cur!=NULL)
    {

        ListNode*_next = cur->next;
        if(_next ==NULL)

        newhead =cur;

        cur->next =prev;
        prev = cur;
        cur =_next;
    }
    return newhead;
}
//查找倒数第K个节点
ListNode *FindNKToTail(ListNode*phead,unsigned int k)
{
    if(phead ==NULL||k<0)
    return NULL;
    ListNode*fast=phead;
    ListNode*slow =phead;
    for(int i =1;i<k;i++)
    {
        if(fast->next ==NULL)
        {
            return NULL;
        }
        else{
      fast =fast->next;
        }
     // fast =fast->next;
    }
    while(fast!=NULL&&fast->next!=NULL)
    {
        fast =fast->next;
        slow =slow->next;
    }
    return slow;
}
//添加节点
ListNode* BuyNode(int x)
{
    ListNode*node = (ListNode*)malloc(sizeof(ListNode));
    node->_val = x;
    node->next = NULL;
    return node;
}
//打印单链表
void PrintList(ListNode*phead)
{
    ListNode*cur = phead;
    while(cur)
    {
        cout<<cur->_val<<"->";
        cur =cur->next;
    }
    cout<<endl;
}
//创建单链表
ListNode*CreatList()
{
    ListNode*head;
    ListNode*node1 = BuyNode(1);
    ListNode*node2 = BuyNode(2);
    ListNode*node3 = BuyNode(3);
    head=node1;
    node1->next =node2;
    node2->next =node3;
    node3->next =NULL;
    return node1;
}
void Test()
{
    cout<<"before"<<endl;
    ListNode*head =CreatList();
    PrintList(head);
  //  cout<<"after"<<endl;
   // ListNode*newhead =ReverseList(head);
   // PrintList(newhead);
    cout<<"查找倒数第K个节点"<<endl;
    ListNode*newhead1 =FindNKToTail(head,2);
    PrintList(newhead1);
}

四: 实现一个Add函数,让两个数相加,但是不能使用+、-、*、/等四则运算符。ps:也不能用++、–等等
//位运算完成+,-

int add(int a,int b)
{
 int c;
    while(c =(a&b))
    {
        a =a^b;
        b= (c<<1);
    }
    return (a^b);
}
//减法,a取反再加1
int sub(int a)
{
   add(a,b);
    return add(~a,1);
}
int main()
{
    int a =-1;
    int b =-2;
    add(a,b);
    sub(a);

    cout<<add(a,b)<<endl;
    cout<<sub(a)<<endl;
      Test();
      return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值