力扣每日(二)

363 阅读18分钟

描述

N 位同学站成一排,音乐老师要请最少的同学出列,使得剩下的 K 位同学排成合唱队形。

设K位同学从左到右依次编号为 1,2…,K ,他们的身高分别为T1,T2,Ti,…,TK ,若存在i(1<=i<=K),T1<T2<Ti<Ti+1<Tk则称这K名同学排成了合唱队形。

通俗来说,能找到一个同学,他的两边的同学身高都依次严格降低的队形就是合唱队形。

例子:

123 124 125 123 121 是一个合唱队形

123 123 124 122不是合唱队形,因为前两名同学身高相等,不符合要求

123 122 121 122不是合唱队形,因为找不到一个同学,他的两侧同学身高递减。

你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

注意:不允许改变队列元素的先后顺序 不要求最高同学左右人数必须相等

数据范围: 1≤i≤3000 1≤n≤3000

这题还是蛮有趣的,我一开始做的时候也是没思路,然后把要求的队列画出来,发现最关键的点就在于找到队列中最高的人,那么找到之后便又该做什么呢?

求左边的人数与右边的人数,求出来之后将以第i人为中间点的所有队列的长度都求出来,选出最大的。

有个问题,怎么求左右两边符合条件的人数?要用到动态规划的思想,从这个人向前遍历,每一个小于她身高的人都要进行判断 dp[i]=max(dp[i],dp[index]+1)dp[i]=max(dp[i],dp[index]+1)

描述

编写一个程序,将输入字符串中的字符按如下规则排序。

规则 1 :英文字母从 A 到 Z 排列,不区分大小写。

如,输入: Type 输出: epTy

规则 2 :同一个英文字母的大小写同时存在时,按照输入顺序排列。

如,输入: BabA 输出: aABb

规则 3 :非英文字母的其它字符保持原来的位置。

如,输入: By?e 输出: Be?y

数据范围:输入的字符串长度满足 1≤length≤1000 1≤n≤1000 

输入描述:

输入字符串

输出描述:

输出字符串

这题算比较有意思,我虽然做出来了,但是很复杂,写的很丑陋,我的思路是把字符串拆分成字母和非字母然后分别处理,字母的部分排序,非字母的部分标记位置,然后新建一个字符串,位置到非字母时就插入非字母。这样最后写出来就比较多。

参考里就很优秀,只用一个字符串存储字母并在遍历的时候就按照顺序保存了,这样保存后的字符串就是排好序的。然后重新遍历原字符串,如果是字母,就把排序后的字符串放进去一个,否则就不操作,这样就可以了。

这里保持原位置就是不操作就可以了,学到了。

描述

IP地址是由4个0-255之间的整数构成的,用"."符号相连。

二进制的IP地址格式有32位,例如:10000011,01101011,00000011,00011000;每八位用十进制表示就是131.107.3.24

子网掩码是用来判断任意两台计算机的IP地址是否属于同一子网络的根据。

子网掩码与IP地址结构相同,是32位二进制数,由1和0组成,且1和0分别连续,其中网络号部分全为“1”和主机号部分全为“0”。

你可以简单的认为子网掩码是一串连续的1和一串连续的0拼接而成的32位二进制数,左边部分都是1,右边部分都是0。

利用子网掩码可以判断两台主机是否在同一子网中。

若两台主机的IP地址分别与它们的子网掩码进行逻辑“与”运算(按位与/AND)后的结果相同,则说明这两台主机在同一子网中。

示例:
I P 地址  192.168.0.1
子网掩码  255.255.255.0

转化为二进制进行运算:

I P 地址   11000000.10101000.00000000.00000001
子网掩码 11111111.11111111.11111111.00000000

AND运算   11000000.10101000.00000000.00000000

转化为十进制后为:
192.168.0.0

I P 地址  192.168.0.254
子网掩码  255.255.255.0

转化为二进制进行运算:

I P 地址 11000000.10101000.00000000.11111110
子网掩码  11111111.11111111.11111111.00000000

AND运算  11000000.10101000.00000000.00000000

转化为十进制后为:
192.168.0.0

通过以上对两台计算机IP地址与子网掩码的AND运算后,我们可以看到它运算结果是一样的。均为192.168.0.0,所以这二台计算机可视为是同一子网络。

输入一个子网掩码以及两个ip地址,判断这两个ip地址是否是一个子网络。

若IP地址或子网掩码格式非法则输出1,若IP1与IP2属于同一子网络输出0,若IP1与IP2不属于同一子网络输出2。

注:

有效掩码与IP的性质为:

  1. 掩码与IP每一段在 0 - 255 之间
  2. 掩码的二进制字符串前缀为网络号,都由‘1’组成;后缀为主机号,都由'0'组成

输入描述:

3行输入,第1行是输入子网掩码、第2,3行是输入两个ip地址
题目的示例中给出了三组数据,但是在实际提交时,你的程序可以只处理一组数据(3行)。

输出描述:

这题很重要!!! 若IP地址或子网掩码格式非法则输出1,若IP1与IP2属于同一子网络输出0,若IP1与IP2不属于同一子网络输出2

这题把我折腾死了,其实思路很简单,不满足条件的输出1,不是共同子网的输出2,共同自我的输出0。就这么容易结果我卡了半天,判断子网掩码的问题上,老是没有处理好,修修改改了半天。

描述

输入一个单向链表,输出该链表中倒数第k个结点,链表的倒数第1个结点为链表的尾指针。 正常返回倒数第k个结点指针,异常返回空指针.

要求:

(1)正序构建链表;

(2)构建后要忘记链表长度。

数据范围:链表长度满足 1≤n≤1000, k≤n  ,链表中数据满足 0≤val≤10000 

本题有多组样例输入。

这题一开始就没仔细看题,不知道人家要求的是不记住长度,然后一通瞎做,题意都没能审清。后面注意到之后,参考答案用递归的方法进行计数其实思路不是很直观,照葫芦画瓢写出来了,然我自己写的话应该不会想着用递归法来求。

描述

输入两个用字符串 str 表示的整数,求它们所表示的数之和。

数据范围: 1≤val≤10000 1≤len(str)≤10000 

输入描述:

输入两个字符串。保证字符串只含有'0'~'9'字符

输出描述:

输出求和后的结果

这题其实思路很简单就是把每一位相加再用一个数字标记进位,关键其实是字符与数字之间的转换,要时刻记住,漏掉之后查了好久,浪费时间。

描述

计算一个浮点数的立方根,不使用库函数。

保留一位小数。

输入描述:

待求解参数,为double类型(一个实数)

输出描述:

输出参数的立方根。保留一位小数。

说句老实话,这题一开始没想到用二分法,估计也是好久不用了,不过想到后写的也不尽如人意。左右边界没考虑好,终止条件没考虑好,所以就一直在改,反正是比较恶心的。现在做题看似多,但是不动脑,不思考,不如不做。

把m个同样的苹果放在n个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?

注意:如果有7个苹果和3个盘子,(5,1,1)和(1,5,1)被视为是同一种分法。

数据范围:0≤n≤10 0≤m≤10 ,1≤m≤10 1≤n≤10

这题说老实话,我真没想出来,确实就是理解不了,也想不到。主要的递归公式就是 f(m,n)=f(m,n1)+f(mn,n)f(m,n)=f(m,n-1)+f(m-n,n)解释就是分两种情况

一是有空盘子的情况,f(m,n-1)当前盘子为空然后剩下的可能组合。

二是没有空盘子的情况,f(m-n,n)每个盘子都至少放一个就剩m-n个,然后再在这n个盘子里面放苹果。

首先这两个情况绝对没有重叠是肯定的。但是第一种情况直接在n-1个盘子里放苹果怎么确保不出现重复呢?

描述

输入一个只包含小写英文字母和数字的字符串,按照不同字符统计个数由多到少输出统计结果,如果统计的个数相同,则按照ASCII码由小到大排序输出。

数据范围:字符串长度满足 1≤len(str)≤1000 1≤len(str)≤1000 

输入描述:

一个只包含小写英文字母和数字的字符串。

输出描述:

一个字符串,为不同字母出现次数的降序表示。若出现次数相同,则按ASCII码的升序输出。

字符统计,我用了最容易想到的办法二维数组,一个标记次数,一个标记字符,然后排序输出。

但是参考里有个思路,就是统计完次数之后,遍历这个次数的数组,然后再按照ASCII码表格的顺序遍历如果等于这个次数就输出。这个思路乍一想有点别扭,其实还是有道理的,就是一种拧巴的感觉。或者反向哈希,根据次数找字符。

描述

Redraiment是走梅花桩的高手。Redraiment可以选择任意一个起点,从前到后,但只能从低处往高处的桩子走。他希望走的步数最多,你能替Redraiment研究他最多走的步数吗?

数据范围:每组数据长度满足 1≤n≤200 1≤n≤200  , 数据大小满足 1≤val≤350 1≤val≤350 

输入描述:

数据共2行,第1行先输入数组的个数,第2行再输入梅花桩的高度

输出描述:

输出一个结果

这题用暴力动态规划很容易就可以求出来,但是参考里有个优化的办法就是使用二分法进行搜索dp数组第i个元素表示长度为i的所有可能组合的字符串中最小的结尾,想法确实有点绕,感觉我是一般不会想出来。

描述

分子为1的分数称为埃及分数。现输入一个真分数(分子比分母小的分数,叫做真分数),请将该分数分解为埃及分数。如:8/11 = 1/2+1/5+1/55+1/110。

注:真分数指分子小于分母的分数,分子和分母有可能gcd不为1!

如有多个解,请输出任意一个。

真要拆分,根据等差数列求和公式可以无限拆分。

而这里肯定希望是有限拆分,说到有限,又观察到这分子分母始终是整数,整数具有离散性,所以考虑能否利用整数的离散性来保证有限

对于分母和分子最大公约数不为1的,把分子和分母同时除以这个公因数。

剩下我们考虑的,全部是分子分母互质。

若当前 分子/分母a/b, (a<b)

因为互质性,显然存在 k使得(k-1)a < b < ka

那么有ka-b < ka-(k-1)a = a

因此 ab=kakb=ka−b+bkb=ka−bkb+bkb=ka−bkb+1k\frac{a}{b} = \frac{ka}{kb} = \frac{ka-b+b}{kb} = \frac{ka-b}{kb} + \frac{b}{kb} = \frac{ka-b}{kb} + \frac{1}{k}ba​=kbka​=kbka−b+b​=kbka−b​+kbb​=kbka−b​+k1​

这里

  1. 拆除的了分母为k分子为1的分数
  2. 剩余部分的分子ka-b小于原来的分子a

这样的拆分方法,保证了能在有限次数内完成拆分

注意,对于拆分出的ka−bkb\frac{ka-b}{kb}kbka−b​ 在下轮拆分时,依然需要先处理公约数.

这题还是涉及到了数学的推导,如何保证最后拆分的结果一定有限,需要进行上述的证明。

描述

将一个英文语句以单词为单位逆序排放。例如“I am a boy”,逆序排放后为“boy a am I”

所有单词之间用一个空格隔开,语句中除了英文字母外,不再包含其他字符

数据范围:输入的字符串长度满足 1≤val≤1000 1≤n≤1000 

注意本题有多组输入

输入描述:

输入一个英文语句,每个单词用空格隔开。保证输入只包含空格和字母。

输出描述:

得到逆序的句子

我只能说,用对了数据结构就很容易,一开始用数组,两次取反确实麻烦,使用栈,天然的就有倒序的能力。

二叉搜索树与双向链表

image.png

这题很重要!!! 这题没做出来,知道用递归,知道中序遍历出来是按顺序的,但是递归函数想的很复杂,怎么也写不出来,答案给的是中序遍历,额外两个节点标记头结点和前一个节点,如果前一个节点是空,那该节点就是头结点,否则就直接连接当前节点与前一个节点,就这么个东西,整了半天没整出来。我也是醉了。

最小的K个数

A priority queue is a container adaptor that provides constant time lookup of the largest (by default) element, at the expense of logarithmic insertion and extraction.

A user-provided Compare can be supplied to change the ordering, e.g. using std::greater would cause the smallest element to appear as the top().

Working with a priority_queue is similar to managing a heap in some random access container, with the benefit of not being able to accidentally invalidate the heap.

复杂链表的复制

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null

image.png

这题我用了最笨的方法,遍历第一次把next连起来,第二次遍历每次都从头遍历到random所在点,其实很费时间,看了参考之后发现很巧妙,

一种方法是使用hash标记每个原来的节点对应的新创建的节点,这样只要新节点不在map中,那就继续创建,否则跳过,这样一来就可以节省时间。

另一种方法,是在原来的每个节点后面新建一个节点,再遍历一遍标记random,最后遍历一遍更改next也是很巧妙的应用。

剑指 Offer 59 - II. 队列的最大值

请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_valuepush_backpop_front均摊时间复杂度都是O(1)。

若队列为空,pop_frontmax_value 需要返回 -1

示例 1:

输入: 
["MaxQueue","push_back","push_back","max_value","pop_front","max_value"]
[[],[1],[2],[],[],[]]
输出: [null,null,null,2,1,2]

示例 2:

输入: 
["MaxQueue","pop_front","max_value"]
[[],[],[]]
输出: [null,-1,-1]

 

限制:

  • 1 <= push_back,pop_front,max_value的总操作数 <= 10000
  • 1 <= value <= 10^5

剑指 Offer 45. 把数组排成最小的数

输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。

 

示例 1:

输入: [10,2]
输出: "102"

示例 2:

输入: [3,30,34,5,9]
输出: "3033459"

 

提示:

  • 0 < nums.length <= 100

这题只能说我着相了,想到的是排序,但是排序的规则过于细化,其实最终的目标就是只要左边加右边的值小于右边加左边的值,那么就可以这样保留,而我想的是第一位怎么样,第二位怎么样,然后长度不同又怎么样,这么做太过于愚蠢,而是没有理解compare的真正威力,最后排序后的数组,第一个数无论和后面哪一个数结合,一定都是比相反结合要小的,这样的话一次类推,最后的结果一定就是我们想要的。

剑指 Offer 56 - I. 数组中数字出现的次数

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

这题很有趣,我确实想到了要用异或的方法,但是这只适用于一个数字,当两个数字出现时,缺乏进一步的思考,如何分离两个数字,依照什么原则?在第一次异或完之后的结果相当于两个数字的异或,那么不同之处在于如果该位为1,说明这一位的数字同,可以依据这种原则进行分组处理。如果最低为1位的值为0属于一组,为1属于另一组。怎么找这个最低为呢?从第一位开始,不断左移 div<<=1;这样就完成了所有思路。非常有趣。

剑指 Offer 48. 最长不含重复字符的子字符串

中等

619

company

字节跳动

请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。

这题也比较有趣,官方使用的是双指针法,但是需要用set不断统计是否重复,我用了动态规划,先遍历一遍统计每个数前一个与它相等的字符的位置,然后动规的时候,如果前一个数的位置小于i-1-dp[i-1]说明可以直接加1,否则就是前一个数到现在的位置的长度。这样遍历下来,时间复杂度为O(n),空间复杂度为O(n);

剑指 Offer 13. 机器人的运动范围

地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?

这题比较有趣,实质上是一个广度优先,但是我却把他想复杂了,实际上,只要我肯画张图把它实际表达出来就能很容易的看出来该怎么做,还是懒得动手,懒得思考。

LCR 191

为了深入了解这些生物群体的生态特征,你们进行了大量的实地观察和数据采集。数组 arrayA 记录了各个生物群体数量数据,其中 arrayA[i] 表示第 i 个生物群体的数量。请返回一个数组 arrayB,该数组为基于数组 arrayA 中的数据计算得出的结果,其中 arrayB[i] 表示将第 i 个生物群体的数量从总体中排除后的其他数量的乘积。

这题不能使用除法

这题太有意思了,其实本质是当前坐标的前后两部分各求一个动态数组,所以需要前向遍历一遍后向遍历一遍,可以在第二次遍历的时候顺便把结果求出来,也可以单独在乘一下,非常巧妙,不一定像例题想的那么复杂,主要还是把握数据的类型以及特点。