《程序员面试经典》——链表

部分文字代码copy模仿,如有雷同,请勿介意小白记录敲代码的过程。

1.链表中倒数第k个结点

输入一个链表,输出该链表中倒数第k个结点。

思路:快慢指针,前一个指针比后一个指针慢k步。

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if(pListHead==NULL||k==0)return NULL;
        ListNode* phead=pListHead,*ptail=pListHead;;
        for(int i=1;i<k;++i){
            if(phead->next!=NULL){
                phead=phead->next;
            }else{
                return NULL;
            }
        }
        while(phead->next!=NULL){
            phead=phead->next;
            ptail=ptail->next;
        }
        return ptail;
    }
};

2.访问单个节点的删除

实现一个算法,删除单向链表中间的某个结点,假定你只能访问该结点。

给定待删除的节点,请执行删除操作,若该节点为尾节点,返回false,否则返回true

思路:不删这个节点了,把下个节点值copy过来,然后删除下个节点

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class Remove {
public:
    bool removeNode(ListNode* pNode) {
        // write code here
        if(pNode==NULL)return NULL;
        if(pNode->next==NULL){
            delete pNode;
            return false;
        }else{
            ListNode* newnode;
        newnode=pNode->next;
        pNode->val=newnode->val;
        pNode->next=newnode->next;
        delete newnode;
        return true;
        }
    }
};

3.链表分割

编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前

给定一个链表的头指针 ListNode* pHead,请返回重新排列后的链表的头指针。注意:分割以后保持原来的数据顺序不变。

思路:创建小数链表和大数链表,最后完成后将两链表连接,注意头结点也有值,需要进行比较。

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        // write code here
        ListNode* small=new ListNode(0);
        ListNode* large=new ListNode(0);
        ListNode* smallhead=small;
        ListNode* largehead=large;
        while(pHead){
            if(pHead->val<x){
                small->next=pHead;
                small=small->next;
            }else{
                large->next=pHead;
                large=large->next;
            }
            pHead=pHead->next;
        }
        large->next=NULL;
        
        small->next=largehead->next;
        return smallhead->next;
        
    }
};

4.链式A+B

有两个用链表表示的整数,每个结点包含一个数位。这些数位是反向存放的,也就是个位排在链表的首部。编写函数对这两个整数求和,并用链表形式返回结果。

给定两个链表ListNode* A,ListNode* B,请返回A+B的结果(ListNode*)。

测试样例:

{1,2,3},{3,2,1}
返回:{4,4,4}

思路:对应位相加,注意是否有进位,最后返回链表长的那个做为结果。

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class Plus {
public:
    ListNode* plusAB(ListNode* a, ListNode* b) {
        // write code here
        ListNode* newlist=new ListNode(0);
        ListNode* p=newlist;
        ListNode* node;
        int c=0;
        int sum;
        int val1,val2;
        while(a!=NULL || b!=NULL || c!=0){
            val1 = (a == NULL ? 0 : a->val);
            val2 = (b == NULL ? 0 : b->val);
            sum = val1 + val2 + c;
            c = sum / 10;
            node = new ListNode(sum % 10);
            
            p->next=node;
            p=node;
            a=(a == NULL ? NULL : a->next);
            b=(b == NULL ? NULL : b->next);
        }
        return newlist->next;
    }
};

5.回文链表

请编写一个函数,检查链表是否为回文。

给定一个链表ListNode* pHead,请返回一个bool,代表链表是否为回文。

测试样例:

{1,2,3,2,1}
返回:true
{1,2,3,2,3}
返回:false

思路:

1>反转链表:可以将原始链表反转,判断反转以后的链表与原始链表是否完全一致,如果一致便返回true,如果不一致则返回false。反转链表需要额外的存储空间,不是特别优秀的方法。

2>栈实现:我们可以想到从中间节点向两侧开始比较,如果全部相同,则返回true,否则返回false,因为无法获得一个节点的前一个节点,这个时候我们可以想到用栈实现,先将链表前半部分的元素分别压入堆栈,然后在遍历后半部分元素的时候同时和栈顶元素进行比较,如果全部相等则返回true,否则返回false。

 特别注意:因为我们不知道链表的的长度,可以通过快慢指针(一个指针每次移动两个,一个指针每次移动一个)来找到中间元素,这样整体只需要遍历链表一次,所需要的栈空间缩小为方法1的一半。

3>递归:递归方法分为尾部递归和首部递归,还有中间递归,一般的尾部递归都可以用循环来实现,对于我们这道题目,递归的时候无法比较第一个元素和最后一个元素,即使知道最后一个元素,也无法获得最后一个元素的前一个元素。所以我们选择首部递归,先递归直到中间的元素,然后比较中间的元素,把比较结果返回,同时保存后半部分下一个要比较的元素(用引用传递可以,用二级指针也可以),递归返回后,如果是true,则继续比较,如果是false,则直接返回false。

方法一:
/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class Palindrome {
public:
    bool isPalindrome(ListNode* pHead) {
        // write code here
         if (pHead == NULL)return false;
        ListNode* reverselist=new ListNode(0);
        ListNode* pa=pHead;
        ListNode* pb;
        reverselist->next=NULL;
        while(pa!=NULL){
            pb=new ListNode(pa->val);
            pb->next=reverselist->next;
            reverselist->next=pb;
            pa=pa->next;
        }
        pa=pHead;
        pb=reverselist->next;
        while(pa!=NULL&&pb!=NULL){
            if(pa->val==pb->val){
                pa=pa->next;
                pb=pb->next;
            }else{
                return false;
            }
        }
        return true;
        
    }
};
方法二:
/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class Palindrome {
public:
    bool isPalindrome(ListNode* pHead) {
        // write code here
        stack<int> s;
        if(pHead==NULL)return false;
        ListNode* p=pHead;
        ListNode* q=pHead;
        s.push(p->val);
        while(q->next!=NULL&&q->next->next!=NULL){
            p=p->next;
            s.push(p->val);
            q=q->next->next;
        }
        
        if(q->next==NULL){
            s.pop();
        }
        while(p->next!=NULL){
            p=p->next;
            if(p->val==s.top()){
                s.pop();
            }
            else{
                return false;
            }
        }
        return true;
    }
};
方法三:
/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class Palindrome {
public:
    bool isPalindrome(ListNode* pHead) {
        // write code here
        ListNode *tail=pHead;
        int length=0;
        while(tail!=NULL){
            length++;
            tail=tail->next;
        }
        return ispd(pHead,&tail,length);
    }
    
    bool ispd(ListNode* pHead,ListNode** tail,int length){
        if(length==0||pHead==NULL){
            return true;
        }
        if(length==1){
            *tail=pHead->next;
            return true;
        }
         if(length==2){
             if(pHead->val==pHead->next->val){
                 *tail=pHead->next->next;
                 return true;
             }else{
                 return false;
             }
           
        }
        bool flag=ispd(pHead->next,tail,length-2);
        if(flag==false)return false;
         ListNode* tail1=*tail;
        if(pHead->val==tail1->val){
                 *tail=tail1->next;
                 return true;
             }else{
                 return false;
             }
    }
};

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HelloHypatia

希望自己的总结对大家有所帮助!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值