剑指Offer_LeetCode_3-12

03.数组中的重复数字

使用unordered_set 容器,容器特性:不再以键值对的形式存储数据,而是直接存储数据的值;容器内部存储的各个元素的值都互不相等,且不能被修改;不会对内部存储的数据进行排序。
默认构造函数创建空的 unordered_set 容器

std::unordered_set<std::string> uset;

其他常用方法:

begin()	返回指向容器中第一个元素的正向迭代器。
end()	返回指向容器中最后一个元素之后位置的正向迭代器。
empty()	若容器为空,则返回 true;否则 falsesize()	返回当前容器中存有元素的个数。
emplace()	向容器中添加新元素,效率比 insert() 方法高。
insert()	向容器中添加新元素。
erase()	删除指定元素。
find(key)	查找以值为 key 的元素,如果找到,则返回一个指向该元素的正向迭代器;反之,则返回一个指向容器中最后一个元素之后位置的迭代器(如果 end() 方法返回的迭代器)。
uset.find(key) == uset.end(), 说明uset中没有key元素

04.二维数组中的查找

在这里插入图片描述
左分支比根小,右分支比根大。
从(0, m-1)开始与目标值比较,目标值大则往右:i++;目标值小则往左:j–;直到到达(n-1,0)

05.替换空格

string的大小和容量

string s;
s.size();
s.length(); //二者执行效果相同

先遍历字符串统计空格个数,扩充string长度

s.resize(length); //将字符串s的长度扩充为length

双指针法,i指向新长度末尾,j指向旧长度末尾,从后向前遍历
s[j]是空格,i的位置填充0、2、%,否则s[i] = s[j]

if(s[j] == ' '){
	s[i] = '0';  //s[i] = "0"这种写法报错了,不知道为什么,只能单引号
	s[--i] = '2';
	s[--i] = '%';
}

06.从尾到头打印链表

  1. 从头到尾遍历并输出到vector,然后翻转
  2. 递归
vector<int> reverse(ListNode* node, vector<int>& a){
	if(node == NULL) return a;
	reverse(node -> next, a);
	a.push_back(node->val);
	return a;
}
vector<int> reversePrint(ListNode* head) {
	vector<int> result;
	reverse(head, result);
	return result;
}

官方题解还有用栈的方法,但是又要遍历链表压入栈,又要把元素依次出栈,感觉没必要,对于这道题来说太复杂了,但是好像突然理解了栈和递归的关系

07.重建二叉树

  1. 数组为空,结束递归
  2. preorder[0]作为根节点
  3. 在inorder中找到根节点的值所在位置,作为切割点
  4. 根据切割点将inorder切割为左右子树的中序遍历
  5. 根据左右子树中序遍历的长度,将preorder切割为左右子树的前序遍历
  6. 分别递归构建左右子树
    vector对象初始化的方法:
    圆括号用来构造vector对象,例如用来说明容量和初始值;花括号用来列表初始化vector对象,花括号内的值即为元素初始值的列表
vector<T> v1  //v1是一个空vector,它潜在的元素是T类型的,执行默认初始化
vecotr<T> v2(v1)  //v2中包含有v1所有元素的副本
vector<T> v2 = v1  //等价于v2(v1)
vector<T> v3(n, val)  //v3包含了n个重复元素,且每个元素的值都是val
vector<T> v4(n)  //v4包含了n个重复执行了值初始化的对象,即v4长度为n,初值为数据类型T默认的初始值,对于int即初值均为0
vector<T> v5{a,b,c,...}  //v5包含了初始值个数的元素,每个元素被赋予相应的初始值
vector<T> v5 = {a,b,c,...}  //等价于 v5{a,b,c,...}

10.斐波那契数列

直接递归会超时
动态规划:转移方程dp[i] = dp[i -1] + dp[i - 2]
所以每次只需要记录dp[i -1]和dp[i - 2]的值,在设置一个中间值tmp,来每次传递新值
还要记得取模

	int n_0 = 0;
    int n_1 = 1;
    for(int i = 0; i < n ; i++){
        int sum = (n_0 + n_1) % 1000000007;
        n_0 = n_1;
        n_1 = sum;
    }
    return n_0; //从0开始的斐波那契数列

这道题通过率低真的很有道理,处处是坑。

  • 青蛙跳台阶问题是从1开始的数列
   int n_0 = 1;
   int n_1 = 1;
   for(int i = 0; i < n; i++){
       int sum = (n_0 + n_1) % 1000000007;
       n_0 = n_1;
       n_1 = sum;
   }
       return n_0;

11.旋转数组的最小数字

不再是递增的时候就是最小数字。
循环时向前比较,这样 i 不容易溢出,同时这样循环需要提前判断输入数组的长度是否为1,是则直接返回。

int minArray(vector<int>& numbers) {
    if(numbers.size() == 1) return numbers[0];
    int i = 1;
    while(i < numbers.size()){
        if(numbers[i] >= numbers[i - 1]) i++;
        else break;
    }
    if(i == numbers.size()) return numbers[0];  //没有旋转,整个数组符合递增序列
    else return numbers[i];
}

12.矩阵的路径

  1. 递归函数的参数和返回值:返回值为布尔值res,记录是否匹配;参数包括递归的元素在矩阵中的位置i,j,当前目标字符在word中的索引k
  2. 终止条件:
    返回false:行列越界;矩阵元素与目标字符不匹配;当前元素已经在上一层递归访问过(可以与上一个条件重合,因为在下述递归逻辑中将访问的元素设为了空字符)
    返回true:k = word.length() - 1,即全部匹配成功
  3. 递归逻辑:
  • 标记当前元素:将word[i][j]修改为空字符,代表已经访问过,避免重复访问
  • 搜索下一单元格:向上下左右进行四层递归,结果使用连接(只要找到一条可行路径就返回),将该结果记录到res
  • 还原当前元素:将word[i][j]还原为初始值
class Solution {
public:
	int rows,cols;
    bool traversal(vector<vector<char>>& board, string word, int i, int j, int k){
        if(i >= rows || i < 0 || j < 0 || j >= cols) return false;
        if(board[i][j] != word[k]) return false;
        if(k == word.length() - 1) return true;
        //这里其实不需要tmp,因为没有在上面三个if下结束该次递归,说明此时word[k] == board[i][j]
        char tmp = board[i][j]; 
        board[i][j] = '\0';
        bool result = (traversal(board, word, i - 1, j, k + 1) ||      //上
                    traversal(board, word, i + 1, j, k + 1) ||         //下
                    traversal(board, word, i, j - 1, k + 1) ||         //左
                    traversal(board, word, i, j + 1, k + 1));          //右
        board[i][j] = tmp; //这里board[i][j] = word[k]即可
        return result;
    }
    bool exist(vector<vector<char>>& board, string word) {
        rows = board.size();
        cols = board[0].size();
        for(int i = 0;i < rows; i++){
            for(int j = 0; j < cols; j++){
            //从word第一个字符开始进入递归,与board[i][j]遍历进行比较
                if(traversal(board, word, i, j, 0)) return true;
            }
        }
        return false;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值