C++剑指offer:从尾到头打印链表、链表反转、复制复杂链表、替换空格、左旋转字符串、数组中重复的数字、二维数组中的查找

从尾到头打印链表

输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
在这里插入图片描述
解:
我的解法可能会有点脱裤子放屁的感觉,先声明一个栈,因为栈是先入后出,所以把链表的值都放到一个栈里面,然后再从栈内把每个val取出来赋值给数组,最后返回数组就可以了。还看到一些更简洁的代码,就是直接用vector来存储链表中的每一个val,然后用vector的reverse函数对数组进行反转,在reverse函数里面传入vector的begin和end就可以实现。

class Solution {
public:
    vector<int> reversePrint(ListNode* head) {
        stack<int> st;
        vector<int> ve;
        while(head){
            st.push(head->val);
            head = head->next;
        }
        while(!st.empty()){
            ve.push_back(st.top());
            st.pop();
        }
        return ve;
    }
};

链表反转

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
解:
在做这道题的时候首先需要直到的就是一个链表的数据结构:
每个链表节点分为两个域:
数据域:存放节点内的实际数据
指针域:存放指向下一个节点的指针

typedef struct oneSt{
int num;
struct one *next;
}st1;//这个是使用typedef对oneSt定义了一个新名字
struct twoSt{
int num;
struct two *next;
}st2;//在这是定义了一个结构体变量st2,后面可以直接使用这个结构体变量

在知道这些之后就可以开始做题了,定义两个结构体再加一个临时的结构体用于传递结构体

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode *cur = head, 
        ListNode *pre = nullptr;
        while(cur != nullptr) {
            ListNode* tmp = cur->next; // 暂存后继节点
            cur->next = pre;           // 修改 next 引用指向,由向后变为向前
            pre = cur;                 // pre 暂存 cur
            cur = tmp;                 // 使用赋值=让cur 访问下一节点
        }
        return pre;//最后返回反转后的头节点
    }
};

复制复杂链表

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
在这里插入图片描述
说实话,第一眼看到这道题觉得好简单,直接一波对next进行复制,然后一运行全错,然后去看别人的题解,受益匪浅,下面就这个题的题解学习后,再记录自己的理解
解:
在本题中首先需要知道的就是map的用法,kv模式下先建立起新老链表之间的映射关系,然后使用map进行链表中指针的复制,最后只需要返回map[head]就可以了
代码中的unordered_map是一个将key和value关联起来的容器,它可以高效的根据单个key值查找对应的value,解法中使用到了两个Node*来建立新老链表的映射。

class Solution {
public:
    Node* copyRandomList(Node* head) {
	if(head == nullptr) return nullptr;//如果老链表是个空链表,直接返回空就可以了
        Node *cur = head;//先定义一个指针,初始化为老链表的头指针
        unordered_map<Node*, Node*> map;//声明map,里面的映射是新老链表的每个节点
        while(cur != nullptr) {//如果cur不是空则执行循环域里面的代码
            map[cur] = new Node(cur->val);//建立原链表和新链表的map映射
 //上面这句代码的意思就是KEY cur对应的是一个新的Node,此Node是一个链表节点,新Node的值是cur->val
            cur = cur->next;//然后将原链表节点向后传递,直到所有的新链表都创建完毕,并都建立起映射
        }
        cur = head;//由于上面对cur向后进行了传递,所以在这需要重新将其指向head头指针,以便于后面进行next和random的复制
        while(cur != nullptr) {
            map[cur]->next = map[cur->next];//将原cur->next复制给KEY cur对应的新链表节点的next
            map[cur]->random = map[cur->random];//将原cur->random复制给KEY cur对应的新链表节点的random
            cur = cur->next;
        }
        return map[head];//此处中括号里面的是原链表的head,这是一个key,其对应的val是新链表的head,至此复杂链表复制完毕
    }
};

替换空格

请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
在这里插入图片描述
解:
这道题就很简单,直接定义一个string对象,把输入中的每个char拿出来与空格对比(==),如果是空格那就在新定义的string对象后面追加"%20",如果不是空格那就把这个char追加到string后面

class Solution {
public:
    string replaceSpace(string s) {
        string str;
        for(auto &c : s){
            if(c==' '){
                str+="%20";
            }else{
                str+=c;
            }
        }
        return str;
    }
};

左旋转字符串

字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
在这里插入图片描述
解:
获取到字符串的长度和n,使用s[i]分割字符串,分割后先向一个新字符串追加后面的一段,然后再追加前面的一段

class Solution {
public:
    string reverseLeftWords(string s, int n) {
        string str;
        for(int i=n;i<s.length();++i){
            str+=s[i];
        }
        for(int j=0;j<n;++j){
            str+=s[j];
        }
        return str;
    }
};

数组中重复的数字

找出数组中重复的数字。在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
在这里插入图片描述
解:
这个解法也是极其妙的,也是使用到了map,这次的key,val分别是使用范围for从nums里面取出来的每个元素,val是一个bool值,在范围for的循环域中首先使用一个if判断,在还没对每个key给val时,if语句里面的判断全是false,也就不会return num,但是当对每个第一次出现的key给上一个true的val后,只要后面有与前面重复的num时,条件就是true,返回这个重复的num,很妙的算法。

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
    unordered_map<int, bool> map;
    for(int &num : nums) {
        if(map[num]) return num;
        map[num] = true;
    }
    return 0;
    }
};

二维数组中的查找

在一个 n * m 的二维数组中,每一行都按照从左到右 非递减 的顺序排序,每一列都按照从上到下 非递减 的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
在这里插入图片描述
解:
这是一道中等难度的题,看到了大神给的绝妙解法,自己也写了一个简易解法,先说自己的解法吧
用到了迭代器进行遍历,最内层用if条件进行与target进行对比,只要相等那就返回true,不相等就啥也不干,直到最后返回false,简单易懂

class Solution {
public:
    bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
        for(auto p=matrix.begin();p!=matrix.end();++p){
            for(auto q=begin(*p);q!=end(*p);++q){
                if(*q==target) return true;
            }
        }
        return false;
    }
};

下面的是大神解法
解:
这个解法就很扣题,把题目里面的条件都用上了,从左往右非递增,从上往下非递减,那么重点来了当要找一个target的时候,我们有4个角作为我们其实位置的备选方案,首先看左上角和右下角,这两个角都有一个共性,那就是要不就是都比target小,要不就是都比target大,这就导致我们无法选择要舍弃的行和列,所以这两个角都不能作为起始位置,所以在这里我们将起始位置定在左下角,假设target=8,左下角那个元素18所在行都大于等于18,所以这一行就可以直接省略,将坐标往上移动,这时的元素是10,这一行的元素都是大于等于10,所以这行也可以省略,再往上移动一行,这一行最左边的元素是3,那这一行的元素就是大于等于3,就有了8出现的可能,所以这时候就需要移动列,往右移动一位是6,6也小于8,继续移动一位,这时的元素是9,9大于8,再就不移动列了,再看9上面的元素都是小于9的,那再往上移动一列,找到target==8

class Solution {
public:
    bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
    int i = matrix.size() - 1, j = 0;
        while(i >= 0 && j < matrix[0].size())
        {
            if(matrix[i][j] > target) i--;
            else if(matrix[i][j] < target) j++;
            else return true;
        }
        return false;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

孤夜寒光

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

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

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

打赏作者

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

抵扣说明:

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

余额充值