幽默刷题DAY3

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_43840280/article/details/119447204

本文为《剑指offer》刷题笔记的总结,花费不到两个月的时间将力扣上《剑指offer》的75道题刷了一遍,遇到不会的知识点或者应该做一些记录的题目都将其写在了往日的博客里。

整体来看,这75道题,涉及到常用的数据结构:数组、字符串、链表、栈、队列、树、图,还有一些常用的数据操作和算法:二分法、哈希表、递归、排序、查找、位运算、动态规划、回溯、滑动窗口、双指针、深度优先搜素(DFS)、贪心。

1、数组

(1)剑指offer03.数组中重复的数字

https://leetcode.cn/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/
幽默数组题,想到的方法都觉得我是傻逼,不过还是以此为基础梳理一下吧要不然就永远是傻逼了
先是最幽默的\(O(n^2)\)时间的,对每个数,查询后面有没有一样的。好消息是空间复杂度\(O(1)\)

但是题目没说我们穷到只有四个寄存器啊!还想到一个计算概论的办法:注意到提示1,数组元素是有范围的,那就开一个\(O(n)\)的数组,cnt[documents[i]]++这种操作就行。扫描一边原数组再扫描一遍cnt,时间\(O(n)\)

但还是觉得有点低能,因为手里没有用的牌太多了。看到这种题,明明先有一个强烈的想法:快排!他又没禁止让我快排,而且这种题好像没有幽默计算概论程设那种让你手写冒泡乃至快排,你他妈直接调库就行了。
那么这个平台的sort函数怎么写呢?哈哈!

复习sort函数

头文件algorithm(不上计算概论的人好像都有一个万能头文件)

sort()函数可以对给定区间所有元素进行排序。它有三个参数sort(begin, end, cmp),其中begin为指向待sort()的数组的第一个元素的指针,end为指向待sort()的数组的最后一个元素的下一个位置的指针,cmp参数为排序准则,cmp参数可以不写,如果不写的话,默认从小到大进行排序。如果我们想从大到小排序可以将cmp参数写为greater()就是对int数组进行排序,当然<>中我们也可以写double、long、float等等。如果我们需要按照其他的排序准则,那么就需要我们自己定义一个bool类型的函数来传入。比如我们对一个整型数组进行从大到小排序:sort(num,num+10,greater<int>());
sort(arr.begin(),arr.end());
沙海拾贝>w<:数组的名字是指针(是吗?)反正可以通过后面+10的方式跳转到后面单个size长度*10这种位置,实现访问下标9的那个元素。但是STL中的Vector,他有自己的方法.begin()和.end(),这里有详细介绍https://zhuanlan.zhihu.com/p/338390842
快排之后扫描有没有挨着的相等,那么就是\(O(n\log n)\)\(O(1)\)

还有想到容器的办法,就是STL的vector他有加入、查找两个功能。vector是不能有重复元素的(这是错的,我记错了,没有的是Set,然后multiset是可以有)。那还是\(O(n)\)\(O(n)\),但是初具现代意识。唉,C++
卧槽不对啊,他传入的就是Vector,怎么可以有重复数字!?我记错了?
有题解想到这个了,用的是Set,我对STL的回忆有点不清楚了。

沙海拾贝2:STL使用方法,长度,插入,查找:len = a.size()
set查找返回iteration,没找到就是end

幽默记录:C++声明变量忘记写类型,结尾忘记写分号(什么忘记母语)

从题解里抄来别的解法,就是说我们【可以破坏原数组】。我是怀着多么虔诚的心灵,我居然没有意识到这一点
就有【原地换位置】的经典办法,把数字t换到下标t去

class Solution {
public:
    int findRepeatDocument(vector<int>& documents) {
        int n=documents.size();
        for(int i=0;i<n;){
            int t=documents[i];
            if(t!=i){
                if(documents[t]==t){
                    return t;
                }else{
                    swap(documents[i],documents[t]);
                }
            }else{
                i++;
				/*注意这里,并不是每一轮都默认++,而是当前i号坑填对了数字i,再后移。
				因为你交换了最初的t和nums[t],新来的nums[t]还需要处理,要不然他就永远不会被操作了。
				不是把关注点落在“我把数字t换到他应该在的位置就好了”而是在“i号坑应该换到数字i”,这是一系列过程。
				因此,题解用的是while。*/
            }
        }
        return -1;
    }
};


(2)剑指offer04.二维数组中的查找。

解法:找标志数。正确思路是首先进行非空判断,即排除matrix=[]和matrix=[[]],然后找标志数,找左下角数字作为标志数,它为第一列最大数字,是本行最小数字。如果target 大于该数则向上查找,否则往右查找。
https://leetcode.cn/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/description/

一开始看错题了,原来是查找。有这么明显的序关系,一开始看成二分了,如果从左上角和右下角开始,会有不知道向右还是向下的问题。

题解们非常tricky地转化了这个问题,他从右上角开始找,把题目反着看一半。题目是向右向下增大,他变成向左减小,向下增大,这不是二分,而是分治。注意判断空的就是了。

(3)剑指offer11.旋转数组的最小数字。

https://leetcode.cn/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/description/
怎么这么沙比的题目啊?直接sort输出最小的不就好了?就连我们不允许动原数组的计算概论题,或者要卷一下速度,也可以\(O(n)\)\(O(1)\)扫描一遍解决。这是在干什么?

这还要二分啊?

二分的平均时间是\(O(\log n)\),好吧,说服我了。

哦!!!!!题目我没看懂,原来是这样的:前半部分是升序的,后面打乱了。
我还是没看懂,这个数组他妈的是一个拼起来的,两部分都是升序的,找分界点。
所以比较中点函数值和右边函数值,如果小的话,说明最小值还在左边;如果大的话,说明最小值在中点右边;如果相等的话,都有可能(因为不是严格的),就只能左移一格。

二分还是注意端点,这个雷这辈子还得踩的。
幽默右移运算符优先级!


while(l<r){
            mid=l +((r-l)>>1);
            if(stock[mid]<stock[r]){
                r=mid;
            }else if(stock[mid]>stock[r]){
                l = mid+1;
            }else{
                r--;
            }
        }

(4)剑指offer14-I.剪绳子。

https://leetcode.cn/problems/jian-sheng-zi-lcof/description/

DP已经忘记了,下次再来吧。

怎么会做不出来啊?
这个题他不能递归,那就用循环。

DP数组应该存储n-1长度的最优解(我怎么又没用STL?)
第二数学归纳法一般地,对于n,
只考虑砍一刀,左侧i的不可再分,右侧n-i的调函数(数组),这种情况下的乘积就是\(i*DP[n-i]\)
还有一个小细节,我一开始本能地觉得i只需要考虑\(i\le (n+1)/2\)的部分就可以了,后来我觉得两边不对称的,右边可以再分。其实还是对称的,如果右边可以再分,遇到的小数字,你肯定在左边的循环中遇到过了。

有没有可能不用切呢?考虑对半切,那就是\(n^2/4<n\),也就是说n大的时候,没有可能,那我手动设置特殊情况。

OK我懂了,我没有错,这个题目有歧义,我看懂了题解
他觉得一定至少切一刀,那么3就是输出2,但是如果递归(数组)的话,比如对i=5,j=2,右边剩下3可以不切的,他所以每一步都比较一下不递归会怎样,他不像我一样考虑前几个数特殊处理。

因为打表超过了100%的CPP用户,笑了我真的……

还有一个数学解法(救命有搞数论的……),他的宗旨是尽可能把绳子分成长度为3的小段,加油数学人!

(5)剑指offer14-II.剪绳子II。

解法:考虑大数越界的情况下的求余问题,可能超过int的范围。大数求余方法包括循环求余(O(N))和快速幂(log2(N))求余。第二者的时间复杂度更低。具体解法

https://leetcode.cn/problems/jian-sheng-zi-ii-lcof/description/

哈哈,想不到吧,我刚从贪心学完数学回来!

想用long long逃课还是失败了,数字太大了,超过long long了。好在这道题还是可以逃课,因为一直mod3就可以了。

哎我是来学习的!好吧大整数我来了
没有大整数啊,题解居然在卷快速幂之类的速度,这素在?

就是把求\(3^n\)变成了求\(9^n\)?闲的?
下次遇到再说吧

笑点解析:Python没有大整数问题

(6)剑指offer17.打印从1到最大的n位数。

https://leetcode.cn/problems/da-yin-cong-1dao-zui-da-de-nwei-shu-lcof/description/

这又是在干什么?考我pow(a,b)函数?
又是一个假的大整数问题,继续逃避!

(7)剑指offer21.调整数组顺序使奇数位于偶数前面。

https://leetcode.cn/problems/diao-zheng-shu-zu-shun-xu-shi-qi-shu-wei-yu-ou-shu-qian-mian-lcof/description/

又想到各种原地换位之类的事情了,
还是从最傻逼想起,空间复杂度开一个O(n)新数组,时间复杂度扫描两次,怎么你了?
和双指针有没有关系?
他没说要排序,别给自己加条件、

ok用双指针做出来了,我的策略是检测慢指针是不是偶数,是的话用快指针抓最近的奇数过来(swap)。注意循环出口是快指针越界,如果一直没有偶数,小心慢指针比快指针还快

逃课快速0offer解法:sort按mod2倒序

(8)剑指offer39.数组中出现次数超过一半的数字。

解法:摩尔投票法或数组排序法。摩尔投票法:记首个元素为n1,众数为x,遍历并统计票数。利用票数和=0可缩小剩余数组区间。当遍历完成时,最后一轮假设的数字为众数。具体解法

https://leetcode.cn/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof/description/

这不就cnt数组吗还有啥办法啊我的活爹?
我智障了,数组内容可以大于数组长度
题目智障了,谁家他妈的商品ID叫-1啊?申金啊????
啊?加bias也不行,因为设置了-1和INT_MAX参数?申金啊?打表就算了,想想怎么办吧,傻逼啊
Hash?有那种有键值对的STL,咋用?
map!成功了

预习(?)map的用法:insert,find,->first,->second
https://zhuanlan.zhihu.com/p/127860466

来点婆罗门解法哈

摩尔排序(我真没听过啊)
很好理解。也是抓住众数的特点。

推论一: 若记 众数 的票数为 +1 ,非众数 的票数为 −1 ,则一定有所有数字的 票数和 >0 。
推论二: 若数组的前 a个数字的 票数和 =0 ,后 (n−a)个数字的 众数仍为 x。

来点数论小天才解法
数组排序法: 将数组 stock 排序,数组中点的元素 一定为众数。
(我草。)

(9)剑指offer40.最小的k个数。

(10)剑指offer41.数组流中的中位数(困难)。解法:小顶堆和大顶堆。具体解法

(11)剑指offer45.把数组排成最小的数。解法:快速排序。具体解法

(12)剑指offer49.丑数。解法:动态规划,丑数只包括因子2,3,5,因此“丑数=某较小丑数*某因子”。 具体解法

(13)剑指offer51.数组中的逆序对。解法:归并排序,使用分治,通过不断划分数组,直至到两个部分时再逐一判断。具体解法

(14)剑指offer53-I.在排序数组中查找数字。

(15)剑指offer53-II.0~n-1中缺失的数字。解法:二分法。 具体解法

(16)剑指offer57-I.和为s的两个数字。

(17)剑指offer57-II.和为s的连续正数序列。解法:滑动窗口。具体解法

(18)剑指offer59-I.滑动窗口的最大值。

(19)剑指offer61.扑克牌的顺子。解法:排序。先对数组执行排序,然后判别重复,最后获得最大/最小的牌。具体解法

(20)剑指offer64.求1+2+...+n。解法:递归+逻辑运算符短路效应。具体解法

(21)剑指offer66.构建乘积数组。解法:上、下三角。根据表格主对角线(全为1),可将表格分为上三角和下三角两部分。分别迭代计算下三角和上三角两部分的乘积。引入辅助变量res=1,首先算B[i]的下三角各元素的乘积,直接乘入B[i],然后计算B[i]的上三角各元素的乘积,记为res,并乘入B[i]。具体解法

2、字符串
(1)剑指offer05.替换空格。

(2)剑指offer20.表示数值的字符串。解法:枚举。在遍历字符串的过程种,记录下4种关键信息(是否包含数字、包含小数点,记录小数点的坐标、包含正负号、包含e,记录e的坐标)。具体解法

(3)剑指offer38.字符串的排列。解法:DFS+剪枝。具体解法

(4)剑指offer48.最长不含重复字符的子字符串。解法:滑动窗口+哈希表。本题采用滑动窗口,利用哈希表来做优化。使用哈希表记录每个字符的下一个索引,然后尽量向右移动尾指针来拓展窗口,并更新窗口的最大长度。如果尾指针指向的元素重复,则头指针直接移动到窗口中重复元素的右侧。具体解法

(5)剑指offer50.第一个只出现一次的字符。解法:哈希表。首先遍历字符串s,使用哈希表统计“各字符数量是否>1”,然后再遍历字符串s,在哈希表中找到首个“数量为1的字符”。具体解法

(6)剑指offer58-I.反转单词顺序。解法:双指针。具体解法

(7)剑指offer58-II.左旋转字符串。

(8)剑指offer67.把字符串转换成整数。解法:大数越界。考虑四种字符首部字符、符号位、非数字字符和数字字符。在数字越界处理方面,在每轮数字拼接前,判断res在拼接后是否超过2147483647,若超过则加上符号位直接返回。具体解法

3、链表

(1)剑指offer06.从尾到头打印链表。

https://leetcode.cn/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/description/
用栈

(2)剑指offer18.删除链表的节点。

(3)剑指offer22.链表中倒数第k个节点。解法:双指针法。具体解法

(4)剑指offer24.反转链表。

(5)剑指offer25.合并两个排序的链表。

(6)剑指offer35.复杂链表的复制。解法:拼接+拆分。考虑构建原节点 1 -> 新节点 1 -> 原节点 2 -> 新节点 2 -> …… 的拼接链表,如此便可在访问原节点的 random 指向节点的同时找到新对应新节点的 random 指向节点。具体解法

(7)剑指offer52.两个链表的第一个公共节点。

4、栈与队列
(1)剑指offer09.两个栈实现队列。

(2)剑指offer30.包含min函数的栈。

(3)剑指offer31.栈的压入、弹出序列。解法:栈的压入与弹出。具体解法

(4)剑指offer59-II.队列的最大值。

5、树
(1)剑指offer07.重建二叉树。解法:在前序遍历结果中,最左边的元素preorder[0]就是二叉树的根节点,而在中序遍历的结果中,找到preorder[0]元素对应的下标,那么preorder[0]左边所有的元素是属于preorder[0]为根的左子树,preorder[0]右边的元素是以preorder[0]为根的右子树,然后进行递归。具体解法

(2)剑指offer26.树的子结构。解法:先序遍历。具体解法

(3)剑指offer27.二叉树的镜像。

(4)剑指offer28.对称的二叉树。解法:后序遍历。过递归函数的返回值来判断两个子树的内侧节点和外侧节点是否相等。具体解法

(5)剑指offer32-I.从上到下打印二叉树。

(6)剑指offer32-II.从上到下打印二叉树。

(7)剑指offer32-III.从上到下打印二叉树。解法:双端队列。具体解法

(8)剑指offer33.二叉搜索树的后续遍历序列。解法:划分左右子树递归。具体解法

(9)剑指offer34.二叉树中和为某一值的路径。解法:回溯法,包含先序遍历+路径记录两部分。具体解法

(10)剑指offer36.二叉搜索树与双向链表。解法:中序遍历。具体解法

(11)剑指offer37.序列化二叉树。解法:DFS深度优先搜素。具体解法

(12)剑指offer54.二叉搜索树的第k大节点。

(13)剑指offer55-I.二叉树的深度。

(14)剑指offer55-II.平衡二叉树。解法:后序遍历。具体解法

(15)剑指offer68-I.二叉搜索树的最近公共祖先。

(16)剑指offer68-II.二叉树的最近公共祖先。解法:后序遍历--回溯。具体解法

6、位运算
(1)剑指offer15.二进制中1的个数。解法:十进制转二进制。首先将十进制数字转化为二进制数,然后在二进制数中查找字符'1'。具体解法

(2)剑指offer16.数值的整数次方。解法:快速幂。具体解法

(3)剑指offer56-I.数组中数字出现的次数。解法:位运算中的异或。具体解法

(4)剑指offer56-II.数组中数字出现的次数。

(5)剑指offer65.不用加减乘除做加法。解法:位运算中的无进位和与异或,进位和与运算规律相同。具体解法

7、动态规划
(1)剑指offer10-I.斐波那契数列。

(2)剑指offer10-II.青蛙跳台阶问题。解法:动态规划。跳上n 级台阶有 f(n)种跳法。在所有跳法中,青蛙的最后一步只有两种情况:跳上1级或2级台阶,即 f(n)=f(n-1)+f(n-2)。 具体解法

(3)剑指offer19.正则表达式匹配。解法:动态规划。具体解法

(4)剑指offer42.连续子数组的最大和。解法:动态规划。具体解法

(5)剑指offer46.把数字翻译成字符串。解法:动态规划。具体解法

(6)剑指offer47.礼物的最大值。

(7)剑指offer60.n个骰子的点数。解法:动态规划。具体解法

(8)剑指offer62.圆圈中最后剩下的数字。解法:约瑟夫环问题,f(n,m)=[f(n-1,m)+m]%n。具体解法

8、图
(1)剑指offer12.矩阵中的路径。解法:DFS+剪枝。标记当前矩阵元素,搜索下一个单元格,还原当前矩阵元素。具体解法

(2)剑指offer13.机器人的运动范围。解法:DFS。通过分析机器人只能从右或下两个方向进行行走才能到达满足条件的格子(可达解)。具体解法

(3)剑指offer29.顺时针打印矩阵。解法:将矩阵的上t、下b、左l、右r四个边界用于打印的res列表,然后进行从左向右、从上到下、从右到左和从下到上的顺序进行循环(根据边界将元素按顺序添加到res列表的尾部,边界向内收缩1,判断边界是否相遇)。 具体解法

9、贪心算法
剑指offer63.股票中的最大利润。解法:贪心算法,因为股票就买卖一次,那么贪心的想法很自然就是取最左最小值,取最右最大值,那么得到的差值就是最大利润。具体解法

10、找规律
(1)剑指offer43.1~n整数中1出现的次数。解法:通过枚举找规律。具体解法

(2)剑指offer44.数字序列中某一位的数字。解法:找规律。具体解法
————————————————

posted @ 2024-04-07 21:23  杰克40001  阅读(13)  评论(0)    收藏  举报