剑指offer(1~3)--二维数组中的查找--替换空格--从尾到头打印链表

1、二维数组中的查找

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

思路分析
在这里插入图片描述
如果你由左到右,由上到下去一个个和目标数值去比较,可以解决问题。但是复杂度是O(n)。所以,我们一开始应该和第一行最右边的数比较,这样就排除了一半的数。如果比它大,那么一定在它下面,如果比它小,那一定在它左边。

牛客网链接

class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        int list = array[0].size()-1;
        int  col= 0;
        while(col<array.size()&&list >= 0)
        {
            if(target > array[col][list])
                col++;
            else if(target<array[col][list])
                list--;
            else
                return true;
        }
        return false;
    }
};

2、替换空格

请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy。则经过替换之后的字符串为We%20Are%20Happy。

思路分析

为什么我可以不开辟空间来直接在原来str所指向的位置操作?
这道题给的返回值的void类型,那么需要在进行改变之后让str指向新的字符空间就可以了。我现在由一个字符串的指针,和这个字符串的长度。那么我假设它str所指向的空间足够大,实际上这个假设应该是成立的,因为字符串要么以数组的形式存在,存在栈上,要么以字符常量的形式存在存放在字符常量区(也就是代码段),但实际上它不可能是存在代码段,因为我们需要对它进行改变,如果存在代码段,是不能改变的。

一个空格替换成%20,原本是一个字符串,替换成了三个字符串。如果采取由前至后挨个查找替换,操作不当很有可能覆盖掉原来字符串中空格后面的字符,所以可以考虑由后至前查找替换,先遍历统计替换之前的长度(oldlen)和替换之后所需要的长度(newlen)。然后由后至前替换
在这里插入图片描述牛客网链接

class Solution {
public:
	void replaceSpace(char *str,int length) {
        int oldlen=0,newlen=0;
        while(str[oldlen]!='\0')
        {
            if(str[oldlen]==' ')
                newlen+=2;
            newlen++,oldlen++;
        }
       //此时str[i]指向\0,而对于字符串来说结尾必须有\0
        newlen++;//给'\0'占一个空间
        str[newlen--]='\0';
        while(newlen>oldlen&&oldlen>=0)
        {
            if(str[oldlen]==' ')
            {
                str[newlen--]='0';
                str[newlen--]='2';
                str[newlen--]='%';
            }
            else
                str[newlen--]=str[oldlen];
            oldlen--;
        }
	}
};

3、从尾到头打印链表

递归

递归是一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。因此递归过程,最重要的就是查看能不能讲原本的问题分解为更小的子问题,这是使用递归的关键。

思路:

我们都知道链表无法逆序访问,那肯定无法直接遍历链表得到从尾到头的逆序结果。但是我们都知道递归是到达底层后才会往上回溯,因此我们可以考虑递归遍历链表,因此三段式如下:

终止条件: 递归进入链表尾,即节点为空节点时结束递归。
返回值: 每次返回子问题之后的全部输出。
本级任务: 每级子任务递归地进入下一级,等下一级的子问题输出数组返回时,将自己的节点值添加在数组末尾。
具体做法:

step 1:从表头开始往后递归进入每一个节点。
step 2:遇到尾节点后开始返回,每次返回依次添加一个值进入输出数组。
step 3:直到递归返回表头。

package main

import . "nc_tools"

/*
 * type ListNode struct{
 *   Val int
 *   Next *ListNode
 * }
 */

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * @param head ListNode类
 * @return int整型一维数组
 */
//全局的数组
var ret []int

func do(head *ListNode) {
	if head != nil {
		do(head.Next) //向深处递归
		ret = append(ret, head.Val)
	}
}

func printListFromTailToHead(head *ListNode) []int {
	do(head) //向深处递归
	return ret
}

使用reverse逆置函数

输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。

思路分析

题设要求从尾到头,我们可以从头到尾遍历List,将val插入vector,然后把vector逆置即可。

/**
*  struct ListNode {
*        int val;
*        struct ListNode *next;
*        ListNode(int x) :
*              val(x), next(NULL) {
*        }
*  };
*/
class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        vector<int> ArrayList;
        if(head==NULL)return ArrayList;
        ListNode*cur=head;
        while(cur)
        {
            ArrayList.push_back(cur->val);
            cur=cur->next;
        }
        reverse(ArrayList.begin(),ArrayList.end());
        return ArrayList;
    }
};

借用栈先进后出

在这里插入图片描述

/**
*  struct ListNode {
*        int val;
*        struct ListNode *next;
*        ListNode(int x) :
*              val(x), next(NULL) {
*        }
*  };
*/
class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        vector<int> ret;
        
        ListNode* cur=head;
        stack<int> s;
        
        while(cur)
        {
            s.push(cur->val);//先把数据都push到栈里
            cur=cur->next;
        }
        cur=head;
        while(!s.empty())
        {
            ret.push_back(s.top());
            s.pop();
        }
        return ret;
    }
};

牛客网链接

Last but not Least
对于这道题不建议直接将单链表逆置,这不符合常理,我只是要这个单链表中的逆序的值,而你却把我的单链表给我逆置了。不建议改变函数参数,因为C++中传指针会把原来的单链表改变。如果我这个单链表还有其他用途,而我并不知道我的单链表被逆置了,就可能造成其他功能的错误。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值