剑指offer刷题记录——代码的鲁棒性

链表中倒数第k个结点

题目描述

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

实现思路

比较直接的办法就是用一指针先遍历整个链表,求得链表长度并减去k,就能知道所求的结点为正数第几个了。然后再用另一指针从头出发遍历即可到达。
还有一种做法是利用栈先进后出的规则,跟倒数是一个意思。依次将结点从头到尾压入栈中,最后弹出k次就能得到。
还有一个办法是利用双指针,先让一指针走k-1步,到达第k个结点,还剩len-k个结点。此时另一指针从头出发,两个指针一起走直到刚开始的指针到达链表尾部时,后出发的指针刚好到正数第len-k+1个结点,即为倒数第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 ;
        ListNode* pPre = pListHead;
        int count=k-1;
        while(count--){
            pHead=pHead->next;
        }
        if(pHead==NULL)
            return NULL;
        while(pHead->next!=NULL){
            pHead=pHead->next;
            pPre=pPre->next;
        }
        return pPre;
    }
};

 

反转链表

题目描述

输入一个链表,反转链表后,输出新链表的表头。

实现思路

反转链表的思路其实就是一个指针往后遍历链表,让下一个结点指向自己,但是要注意为了不丢失后面的结点,保证指针正确往后遍历,还需要一个指针来保存后面结果。
总结起来就是,一个指针实现反转操作,最后成为反转链表的头节点,另一指针维护这个遍历过程。

具体实现

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
        if(pHead==NULL||pHead->next==NULL)
            return pHead;
        ListNode* curList = pHead;
        ListNode* newList = NULL;
        while(curList!=NULL){
            ListNode* next = curList->next;
            curList->next = newList;
            newList = curList;
            curList = next;
        }
        return newList;
    }
};

 

合并两个排序的链表

题目描述

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

实现思路

还是,还是,还是要用到两个指针!做链表的题目最怕的就是遍历着遍历着然后链表丢了。
这个题目其实很明了了,首先定义一个答案指针要用来指向较小数的链表头部,方便最后返回。然后不断往后遍历两个链表并比较大小,用另一指针往后存储较小数即可。

具体实现

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        if(pHead1==NULL)
            return pHead2;
        if(pHead2==NULL)
            return pHead1;
        ListNode* res = NULL;
        ListNode* cur = NULL;
        while(pHead1!=NULL&&pHead2!=NULL){
            if(pHead1->val <= pHead2->val){
                if(res==NULL){
                    cur=pHead1;
                    res=cur;
                }
                else{
                    cur->next=pHead1;
                    cur=cur->next;
                }
                pHead1=pHead1->next;
            }
            else {
                if(res==NULL){
                    cur=pHead2;
                    res=cur;
                }
                else{
                    cur->next=pHead2;
                    cur=cur->next;
                }
                    pHead2=pHead2->next;
            }
        }
        if(pHead1==NULL)
            cur->next=pHead2;
        else
            cur->next=pHead1;
        return res;
    } 
};

 

树的子结构

题目描述

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

实现思路

看到别人写的一个递归版本真的太厉害了,简单易懂。就是不断地将A的子结点的子树与B做比较,如果B的结点都比较完了还没报错则返回正确;如果A的结点都比较完了还没返回正确,说明B不可能是A的子树,则返回错误。

具体实现

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        if(pRoot1==NULL||pRoot2==NULL)
            return false;
        return isSubtree(pRoot1,pRoot2)
            ||HasSubtree(pRoot1->left, pRoot2)
            ||HasSubtree(pRoot1->right, pRoot2);
    }
    bool isSubtree(TreeNode* pRoot1, TreeNode* pRoot2){
        if(pRoot2==NULL)
            return true;
        if(pRoot1==NULL)
            return false;
        return pRoot1->val==pRoot2->val
            &&isSubtree(pRoot1->left,pRoot2->left)
            &&isSubtree(pRoot1->right,pRoot2->right);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值