剑指offer刷题数据结构

Posted 非晚非晚

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指offer刷题数据结构相关的知识,希望对你有一定的参考价值。

记录在Leetcode刷《剑指offer》的笔记,希望提高自己的算法基础和编程水平。这一篇文章刷的是数据结构的题目集合,在CSDN做一下记录,随时更新,一起学习吧。

刷题链接:https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/55187i/

1. 剑指 Offer 05. 替换空格

  • 题目

在这里插入图片描述

  • 提交答案:

思路:定义一个空字符串myStr,遍历输入字符串s,遇到空格就把"%20"加入新字符串myStr,否则就添加s[i]。

class Solution {
public:
    string replaceSpace(string s) {
        string str = "%20";
        string myStr;
        for(int i = 0; i < s.size(); i++)
        {
            if(s[i] == ' ')
            {
                myStr += str;
            }
            else
            {
                myStr += s[i];
            }
        }
        return myStr;
    }
};
  • 原题解答:

思路:先计算空格数,对原string扩容,然后倒序遍历空格,依次加入’%’, ‘2’, ‘0’。

class Solution {
public:
    string replaceSpace(string s) {
        int count = 0, len = s.size();
        // 统计空格数量
        for (char c : s) {
            if (c == ' ') count++;
        }
        // 修改 s 长度
        s.resize(len + 2 * count);
        // 倒序遍历修改
        for(int i = len - 1, j = s.size() - 1; i < j; i--, j--) {
            if (s[i] != ' ')
                s[j] = s[i];
            else {
                s[j - 2] = '%';
                s[j - 1] = '2';
                s[j] = '0';
                j -= 2;
            }
        }
        return s;
    }
};

2. 剑指 Offer 06. 从尾到头打印链表

  • 题目
    在这里插入图片描述

  • 提交答案

思路:遍历list,依次赋值给vector,然后利用reverse函数对vector反转。

这里用的reverse属于算法的函数,其实也可以直接对list使用,不过这里只给了头指针。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> reversePrint(ListNode* head) {
        vector<int> vec;
        auto p = head;
        while(p != NULL)
        {
            vec.push_back(p->val);
            p = p->next;
        }
    reverse(vec.begin(), vec.end());
    return vec;
    }
};
  • 原题解答

思路:递归法,递归原本就属于一种逆序运行的算法。

class Solution {
public:
    vector<int> reversePrint(ListNode* head) {
        recur(head);
        return res;
    }
private:
    vector<int> res;
    void recur(ListNode* head) {
        if(head == nullptr) return;
        recur(head->next);
        res.push_back(head->val);
    }
};

3. 剑指 Offer 09. 用两个栈实现队列

  • 题目

在这里插入图片描述

  • 提交答案

思路:使用A stack存储队列,使用B stack用于删除。由于每次都要清空B,提交的答案耗时间太长。。

class CQueue {
private:
    stack<int> A;//存储队列
    stack<int> B;//用作删除元素

public:
    CQueue() {
        
    }
    
    void appendTail(int value) {
        A.push(value);
    }
    
    int deleteHead() {
        if(A.size() == 0)
        return -1;
        while(A.size() !=0)
        {
            int x = A.top();
            A.pop();//删除
            B.push(x);
        }
        int temp = B.top();
        B.pop();
        while(B.size() != 0)
        {
            int x = B.top();
            B.pop();
            A.push(x);
        }
        return temp;
    }
};

/**
 * Your CQueue object will be instantiated and called as such:
 * CQueue* obj = new CQueue();
 * obj->appendTail(value);
 * int param_2 = obj->deleteHead();
 */
  • 解题思路

思路:同样是使用A和B,A用于保存,B用于删除,不过B不清空,只要有就可以删除。

class CQueue {
public:
    stack<int> A, B;
    CQueue() {}
    void appendTail(int value) {
        A.push(value);
    }
    int deleteHead() {
        if(!B.empty()) {
            int tmp = B.top();
            B.pop();
            return tmp;
        }
        if(A.empty()) return -1;
        while(!A.empty()) {
            int tmp = A.top();
            A.pop();
            B.push(tmp);
        }
        int tmp = B.top();
        B.pop();
        return tmp;
    }
};

4. 剑指 Offer 20. 表示数值的字符串

  • 题目

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100"、“5e2”、"-123"、“3.1416”、"-1E-16"、“0123"都表示数值,但"12e”、“1a3.14”、“1.2.3”、"±5"及"12e+5.4"都不是。

  • 提交答案

思路太繁琐

  • 题目解析

用哈希表来表示。状态是按照string从左只右依次定义的,输入数据后,状态会跳转。

在这里插入图片描述
代码示例:

说明:

  1. states是个数组,表示9中状态。数组的元素为unordered_map类型。
  2. d表示数字
  3. s表示正负号
  4. c表示dot或者空格
find(key);//查找键key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回map.end();
class Solution {
private:
    unordered_map<char,int> states[9]={
        {{' ',0}, {'s',1}, {'d',2}, {'.',4}},   //! 0.
        {{'d',2}, {'.',4}},                     //! 1.
        {{'d',2}, {'.',3}, {'e',5}, {' ',8}},   //! 2.
        {{'d',3}, {'e',5}, {' ',8}},            //! 3.
        {{'d',3}},                              //! 4.
        {{'s',6}, {'d',7}},                     //! 5.
        {{'d',7}},                              //! 6.
        {{'d',7}, {' ',8}},                     //! 7.
        {{' ',8}}                               //! 8.
    };
public:
    bool isNumber(string s) {
        int p=0;
        char t;
        for(auto c:s){
            if(c>='0'&&c<='9') t='d';
            else if(c=='+'||c=='-') t='s';
            else if(c=='e'||c=='E') t='e';
            else if(c=='.'||c==' ') t=c;
            else t='?';
            auto it=states[p].find(t);
            if(it==states[p].end()) return false;//没有找到
            p=(int)it->second;//提取下一个状态
        }//遍历结束后,查看p的状态
        return p==2||p==3||p==7||p==8;
    }
};

5. 剑指 Offer 24. 反转链表

在这里插入图片描述

  • 提交答案

思路:分3种情况,1个元素,2个元素,3个元素。最主要的是3个元素,断开链接进行移动。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == NULL)
        return NULL;
        
        auto p1 = head;
        p1 = p1->next;
        if(p1 == NULL)//只有一个
        {
            return head;
        }
        else if(p1->next == NULL)//2个
        {
            head->next = NULL;//补null
            p1->next = head;
            return p1;
        }
        else//3个以上
        {
            head->next = NULL;//补null
            auto p2 = p1->next;
            while(p2 != NULL)
            {
                //head和p1交换
                p1->next = head;

                //移动
                head = p1;
                p1 = p2;
                p2 = p2->next;
            }
            p1->next = head;
            return p1;
        }
    }
};
  • 题目解析

思路:只需要两个指针遍历,只需要定义一个暂时的指针,保存下一个地址。代码量少耗内存较多。

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode *cur = head, *pre = nullptr;
        while(cur != nullptr) {
            ListNode* tmp = cur->next; // 暂存后继节点 cur.next
            cur->next = pre;           // 修改 next 引用指向
            pre = cur;                 // pre 暂存 cur
            cur = tmp;                 // cur 访问下一节点
        }
        return pre;
    }
};

6. 剑指 Offer 30. 包含 min 函数的栈

  • 题目在这里插入图片描述
  • 题目解析

思路:A是正常栈,B为非严格排序栈。只需要A和B的栈顶元素相同时,才弹出B。

class MinStack {
public:
    stack<int> A, B;
    MinStack() {}
    void push(int x) {
        A.push(x);
        if(B.empty() || B.top() >= x)//递减排序
            B.push(x);
    }
    void pop() {
        if(A.top() == B.top())
           	B.pop();
        A.pop();
    }
    int top() {
        return A.top();
    }
    int min() {
        return B.top();
    }
};

8. 剑指 Offer 58 - II. 左旋转字符串

在这里插入图片描述

  • 提交代码

思路:这题主要是考察string各种方法的熟练程度。截取字符串,然后删除提取部分,赋值末尾即可。

class Solution {
public:
    string reverseLeftWords(string s, int n) {
        string str;
        str.assign(s, 0, n);//从0开始的n个字符,也可以用string的substr方法
        s.erase(0, n);//删除0到n
        for(int i = 0; i < n; i++)
        {
            s += str[i];
        }
        return s;
    }
};
  • 题目解析

思路:方法更简单明了。

class Solution {
public:
    string reverseLeftWords(string s, int n) {
        return s.substr(n, s.size()) + s.substr(0, n);
    }
};

9. 剑指 Offer 59 - I. 滑动窗口的最大值

在这里插入图片描述

提交答案

思路:先写一个滑动窗口k最大值函数,然后在滑动时每次调用该函数。时间复杂度比较高,属于暴力方法。

class Solution {
public:
    int find_max(vector<int>& nums)
    {
        int max_num = nums[0];
        for(int i = 1; i < nums.size(); i++)//找出最大值
        {
            if(nums[i] > max_num)
                max_num = nums[i];
        }
        return max_num;
    }
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        if(nums.size() == 0)
        {
            return nums;
        }
        vector<int>temp;
        for(int i = 0; i < nums.size() - k + 1; i++)
        {
            vector<int>temp_nums;
            for(int j = 0; j < k; j++)
            {
                temp_nums.push_back(nums[i + j]);
            }
            temp.push_back(find_max(temp_nums));
        }
        return temp;
    }
};
  • 题目解析

思路:双端队列(还没研究)

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        //判断特殊情况
        int n = nums.size();
        if(n < k || k <= 0) return 以上是关于剑指offer刷题数据结构的主要内容,如果未能解决你的问题,请参考以下文章

java刷题-剑指offer 07 重建二叉树

剑指offer系列刷题第一篇——寻找单身狗

java刷题-剑指offer 12 矩阵中的路径

剑指offer刷题数据结构

java刷题-剑指offer 11 旋转数组的最小数字

leetcode刷题总目录