剑指offer刷题笔记

一、字符串 

字符串扩容:size()是已经拥有的元素大小,而capacity()是能够装下的元素大小。resize(n)是创建了n个元素,reverse(n)是申请了n个元素的空间,不可以直接访问。

双指针,i j按照一定条件移动

字符串反转:reverse[first, last)

class Solution {
public:
    bool integer(string s) {
        //判断是否是整数
        int size = s.size();
        int posOpr = -1;
        for(int i = 0; i < size; ++i) {
            if(i == 0 && (s[i] == '+' || s[i] == '-')) {
                posOpr = 0;
                continue;
            }
            if(s[i] < '0' || s[i] > '9') return false;
        }
        if(posOpr == size - 1) return false;
        else return true;
    }

    bool decimal(string s) {
        //判断是否是小数
        int size = s.size();
        if(size < 2) return false; 
        int posPoint = -1, posOpr = -1;
        for(int i = 0; i < size; ++i) {
            if(s[i] == '.') {
                posPoint = i;
                break;
            }
        }
        if(posPoint == -1) return false;
        for(int i = 0; i < size; ++i) {
            if(i == 0 && (s[i] == '+' || s[i] == '-')) {
                posOpr = 0;
                continue;
            }
            if(i != posPoint && (s[i] < '0' || s[i] > '9')) return false;
        }
        if(posPoint == size - 1) {
            if(s[posPoint - 1] < '0' || s[posPoint - 1] > '9') return false;
        }
        if(posOpr == size - 1) return false;

        else return true;
    }

    bool isNumber(string s) {
        //判断有没有e/E,没有的话可以整个视为整数or小数,有的话分为整数/小数 e/E 整数
        int size = s.size();
        int start = -1, index = -1, end = -1;
        //去除前空格
        for(int i = 0; i < size; ++i) {
            if(s[i] != ' ') {
                start = i;
                break;
            }
        }
        //去除尾空格
        for(int i = size - 1; i >= 0; --i) {
            if(s[i] != ' ') {
                end = i;
                break;
            }
        }

        if(start == -1 || end == -1) return false; //全是空格

        //查找是否有断点E/e
        for(int i = start; i <= end; ++i) {
            if(s[i] == ' ') continue;
            if(s[i] == 'e' || s[i] == 'E') {
                index = i;
                break;
            }
        }

        if(index == -1) {
            string str = s.substr(start, end - start + 1);
            if(integer(str) || decimal(str)) return true;
        }
        else {
            if(index == end || index == start) return false;
            string str1 = s.substr(start, index - start);
            string str2 = s.substr(index + 1, end - (index + 1) + 1);
            if((integer(str1) || decimal(str1)) && integer(str2)) return true;
        }
        return false;

    }
};

 模拟题一直是我的弱项,分块的思想去做,然后debug会好做一点。主要的思路:判断有没有e/E,没有的话可以整个视为整数or小数,有的话分为整数/小数 e/E 整数。此外'+' '-'和‘.’的小数情况容易漏,这道题应该是hard难度。

二、链表

链表反转:p1 p2 和临时tmp

数组反转:reverse(res.begin(), res.end())

堆:反转输出第一时间要想到栈 stack

链表反转,如果面试出了这个,大概面试官很想要我0.0 

1、暴力方法:遍历第一次解决next,并设置两个哈希表,由老链表节点-顺位 顺位-新链表节点,第二次遍历把random解决。

2、unordered_map的用法:

初始化:unordered_map<int, string> mp

插入:mp[value] = keyname; 对应value的keyname值覆盖,若value不存在,则插入这对元素

           mp.insert(pair<int, string>(value, keyname));

查找:auto x = mp.find(value);  x->first  x->second

三、双指针

根据value删除结点,两个注意事项:需要删除的节点是头结点还是中间节点;中间节点循环的条件。

倒数数字的前一位 = 链表总数 - 倒数数字

双指针:设置链表头,使得头结点的比较和中间节点一致

双指针比较节点

有点快排的味道

两数之和的题,还加了个递增的限制条件

去除头、中间、末尾的空格,然后反转单词,再整体反转。在反转单词时最后一个单词不会反转需要注意。

string用法:

子串:s.substr(pos, n); 由pos开始的n个字符组成的字符串

拼接:string str = str1 + str2

访问字符串字符:str[2] str.at(2)

插入:str.insert(pos,  const string&str); 在位置 pos 处插入字符串 str

删除:str.erase(pos, n); 在位置 pos 处插入字符串 str

四、栈与队列

两个栈实现一个队列,入栈放在stk1,出栈先判断stk2是否为空,如果为空,则把stk1全部移入再出栈,然后不为空则直接出栈.

思路:一个辅助栈用于记录当前的最小值

思路:保证deque中是非递增,双指针,左指针考虑nums[left - 1]和deque.front是否相同,右指针保证取到的值在deque处于非递增。

deque的用法:

front() 返回头部第一个元素

back() 返回尾部第一个元素

push_back(num) 尾部添加元素

push_front(num) 头部添加元素

pop_back(num) 删除容器最后一个元素

pop_front(num) 删除容器第一个元素

insert(pos, num) 在pos位置插入一个num元素

erase(begin(), end()) 删除区间的数值,返回下一个数据的位置

erase(pos) 删除pos位置的数据

queue的用法:

push(num) 队尾添加元素

pop() 队头删除元素

front() 返回队头第一个元素

back() 返回队尾第一个元素

deque实现单调队列

五、搜索与回溯

广度优先遍历:层序遍历(迭代法)

深度优先遍历:先序遍历、中序遍历、后序遍历(递归法、迭代法)

递归模板:

  • 确定递归函数的参数和返回值
  • 确定终止条件
  • 确定单层递归的逻辑

原本的root->left会被替换,所以一开始需要保存。

回溯+DFS图搜索

回溯模板:

  • 回溯函数模板返回值以及参数
  • 回溯函数终止条件
  • 回溯搜索的遍历过程

 for循环可以理解是横向遍历,backtracking(递归)就是纵向遍历

void backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

本题思路:

  • 使用二维bool数组记录之前的位置是否已经被访问过,如果已经被访问过,说明此路不通;
  • 剪枝:当前遍历到的 board[i][j] 不等于word对应位置的字符,说明此路也是不通的;
  • 递归地去 board[i][j] 的上下左右四个方向去找路径;
  • 递归结束的条件:str == word 成立,说明找到这条路径,此时返回 true

使用广度优先搜索(BFS)

求取每个数字的位数:x%10 x/10

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值