【剑指Offer】剑指Offer题解(一)

<1> 替换空格

题目链接

描述

请实现一个函数,将一个字符串s中的每个空格替换成“%20”。
例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
数据范围:0 ≤ len(s) ≤ 1000 。保证字符串中的字符为大写英文字母、小写英文字母和空格中的一种。

示例1

输入:“We Are Happy”
返回值:“We%20Are%20Happy”

示例2

输入:" "
返回值:“%20”

思路分析
先计算出字符串的长度,在计算空格的长度,由此计算出现需的数组长度,再利用双指针遍历s放入自己创建的数组中,遇到空格就换成三个字符:'%' '2' '0'

char* replaceSpace(char* s ) {
    int sz = strlen(s);
    //统计空格数
    char* p = s;
    int count = 0;
    while(*p != 0)
    {
        if(*p == ' ')
        {
            count++;
        }
        p++;
    }
    sz += 2 * count;
    char* str = (char*)malloc(sizeof(char) * sz + 1);
    //双指针
    p = s;
    int i = 0;//str
    while(*p != 0)
    {
        if(*p == ' ')
        {
            str[i++] = '%';
            str[i++] = '2';
            str[i++] = '0';
        }
        else
        {
            str[i++] = *p;
        }
        p++;
    }
    return str;
}

<2> 从尾到头打印链表

题目链接
描述

输入一个链表的头节点,按链表从尾到头的顺序返回每个节点的值(用数组返回)。
如输入{1,2,3}的链表如下图:
在这里插入图片描述
返回一个数组为[3,2,1]
0 <= 链表长度 <= 10000

示例1

输入:{1,2,3}
返回值:[3,2,1]

示例2

输入:{67,0,24,58}
返回值:[58,24,0,67]

思路分析
这道题最直观的就是把链表反转然后顺序输出,但是太过复杂,这里推荐采用递归。通过递归的性质就是先递归到最后再存储到数组中。

void _printListFromTailToHead(struct ListNode* head, int* temp, int* i)
{
    if(head == NULL)
    {
        return;
    }
    _printListFromTailToHead(head->next, temp, i);
    temp[*i] = head->val;
    (*i)++;
}

int* printListFromTailToHead(struct ListNode* listNode, int* returnSize ) {
    //计算链表长度
    int count = 0;
    struct ListNode* cur = listNode;
    while(cur)
    {
        count++;
        cur = cur->next;
    }
    int* temp = (int*)malloc(sizeof(int) * count);
    int i = 0;
    _printListFromTailToHead(listNode, temp, &i);
    *returnSize = i;
    return temp;
}

当然这道题也可以利用栈先进后出的性质来求解。


<3> 二叉树的下一个结点

题目链接

描述

给定一个二叉树其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的next指针。下图为一棵有9个节点的二叉树。树中从父节点指向子节点的指针用实线表示,从子节点指向父节点的用虚线表示
在这里插入图片描述

示例:

输入:{8,6,10,5,7,9,11},8
返回:9
解析:这个组装传入的子树根节点,其实就是整颗树,中序遍历{5,6,7,8,9,10,11},根节点8的下一个节点就是9,应该返回{9,10,11},后台只打印子树的下一个节点,所以只会打印9,如下图,其实都有指向左右孩子的指针,还有指向父节点的指针,下图没有画出来
在这里插入图片描述

数据范围:节点数满足1 ≤ n ≤ 50 ,节点上的值满足1 ≤ val ≤ 100
要求:空间复杂度O(1) ,时间复杂度O(n)
输入描述:
输入分为2段,第一段是整体的二叉树,第二段是给定二叉树节点的值,后台会将这2个参数组装为一个二叉树局部的子树传入到函数GetNext里面,用户得到的输入只有一个子树根节点
返回值描述:
返回传入的子树根节点的下一个节点,后台会打印输出这个节点

示例1

输入:{8,6,10,5,7,9,11},8
返回值:9

示例2

输入:{8,6,10,5,7,9,11},6
返回值:7

示例3

输入:{1,2,#,#,3,#,4},4
返回值:1

示例4

输入:{5},5
返回值:“null”
说明:不存在,后台打印"null"

思路分析

① 递归

先利用next指针找到根节点,然后开始中序遍历,把所有的节点放入创建的数组中,再遍历数组找到题目所给节点的下一个节点(注意最后一个节点不行)

void InOrder(struct TreeLinkNode* root, struct TreeLinkNode** tmp, int* i)
{
    if(root == NULL)
    {
        return;
    }
    InOrder(root->left, tmp, i);
    tmp[*i] = root;
    (*i)++;
    InOrder(root->right, tmp, i);
}

struct TreeLinkNode* GetNext(struct TreeLinkNode* pNode ) {
    struct TreeLinkNode* root = pNode;
    //找根节点
    while(root->next)
    {
        root = root->next;
    }
    struct TreeLinkNode* tmp[50];
    int i = 0;
    InOrder(root, tmp, &i);
    //找pNode
    for(int j = 0; j < i + 1; j++)//不能是最后一个
    {
        if(tmp[j]->val == pNode->val)
        {
            return tmp[j + 1];
        }
    }
    return NULL;
}

② 分情况查找

分成三种情况:
在这里插入图片描述

struct TreeLinkNode* GetNext(struct TreeLinkNode* pNode ) {
    if(pNode->right)
    {
        pNode = pNode->right;//下一个节点的左下节点
        while(pNode->left)
        {
            pNode = pNode->left;
        }
        return pNode;
    }
    else
    {
        //父节点
        struct TreeLinkNode* father = pNode->next;
        if(father == NULL)
        {
            return NULL;
        }
        
        if(pNode == father->left)
        {
            return father;
        }
        else
        {
            while(father)
            {
                struct TreeLinkNode* next = father->next;
                if(next && next->left == father)
                {
                    return next;
                }
                father = next;
            }
            return NULL;
        }
    }
}


纸上得来终觉浅,绝知此事要躬行。

  • 73
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 110
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

命由己造~

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值