LeetCode刷题日记(序&Day1)
今天是正式启动LeetCode刷题计划的第一天,主要是为了提升代码能力以及面向研究生考试/面试。我会通过博客记录答题的思路、过程与主要代码。思路/代码风格若有问题,欢迎评论区讨论~(如果有哪天没有更新也请大家督促呀希望大家都可以考上自己的心仪院校/收获心仪的offer)奥利给!
1539. 第 k 个缺失的正整数(第32场周赛issue 1)
思路:
二分法:确定一个开始位置 start 和结束位置 end,每次对中间的下标mid元素进行比较,如果arr[mid] >= mid + k + 1(+1的原因是数组下标从0开始)则 对前一半进行递归,否则对后一半进行递归。二分法尤其要注意处理的是一些细节问题,如因为我们在偶数个数时选择了下标较小者为mid,因此在对后半部分进行递归时要从mid + 1开始,而对前半部分进行递归时则不用,否则会出现数组越界等问题。
算法的复杂度:
递归式为T(n)=T(n/2)+O(1),由Master 定理知,算法的时间复杂度为O(logn)。因为没有产生额外空间,所以算法的空间复杂度为O(1)。
代码:
class Solution {
public:
int RecursionFindK(vector<int>& arr, int k, int start, int end)
{
if(start == end)
{
if(arr[start] >= start + k + 1)
return start + k;
else
return start + k + 1;
}
int mid = (end + start) / 2; //(end - start) / 2 + start
if(arr[mid] >= mid + 1 + k)
{
if(mid == 0)
{
return k;
}
return RecursionFindK(arr, k, start, mid);
}
else
{
return RecursionFindK(arr, k, mid + 1, end);
}
}
int findKthPositive(vector<int>& arr, int k) {
int res = RecursionFindK(arr, k, 0, arr.size() - 1);
return res;
}
};
1540. K 次操作转变字符串(第32场周赛issue 2)
思路:
本题的实质是找到1-25中出现最多次的数字,然后进行一个简单的处理得到最少次数MinTimes,将其与k进行比较即可。为什么这么说呢,下面进行简单的剖析:
因为只能做字母的循环变化,所以我们只要知道字符串s中一个字母要经过x次变化能变成字符串t对应位置字母,则只要i=x+26n(n
∈
\in
∈N),则可以将该字母变为所要字母。那么我们首先进行一次处理,使用一个大小为26的数组来存放所需变化次数的个数,如count[1]表示需要进行1+26n次变化的字母有count[1]个。最后我们找出count数组中的最大数MaxTimes,然后通过 (MaxTimes - 1) * 26 + MaxNum即可求得最少变换次数MinTimes。如果MinTimes
≤
\le
≤k,则可以变换,否则不可变换。
注意:题目隐含意思要求字符串s与字符串t长度相同,否则无法变化,因为变换操作中没有删除/增加字符串,因此最开始要判断一下两个字符串的长度,如果长度不同,则返回false。
算法的复杂度:
将字符串处理为int数组只要扫描一遍字符串即可,加上最后对int数组的扫描,时间复杂度为O(n+26)=O(n)。唯一开辟的额外空间为大小为26的int数组,因此空间复杂度为O(26)=O(1)。
代码:
class Solution {
public:
bool canConvertString(string s, string t, int k) {
if(s.size() != t.size())
return false;
int count[26] = {0};
for(int i = 0; i < s.size(); ++i)
{
int temp = t[i] - s[i];
if(temp >= 0)
++count[temp];
else
++count[temp + 26];
}
int MaxTimes = 0, MaxNum = 0;
for(int i = 1; i < 26; ++i)
{
if(MaxTimes <= count[i])
{
MaxTimes = count[i];
MaxNum = i;
}
}
int MinTimes = (MaxTimes - 1) * 26 + MaxNum;
if(MinTimes <= k)
return true;
else
return false;
}
};
1541. 平衡括号字符串的最少插入次数(第32场周赛issue 3)
思路:
此题只要列举出各种情况,直接处理即可。使用一个变量LeftNum来记录当前在最左边还未处理的 ‘(’ 的个数。使用一个 bool 变量NeedSecondRight 来标记当前是否需要第二个 ‘)’ 。如果遇到 ‘(’ 则将 LeftNum加一 ,此时注意如果 NeedSecondRight 为 true ,则还要将 res加一 。如果遇到的是 ‘)’ 且目前没有未匹配的 ‘(’ ,则 res加一 ,即添加一个 ‘(’ ;若有未处理的 ‘(’ 则将 LeftNum减一 并将 NeedSecondRight 置为 true ;如果此时是第二个 ‘)’ 则将 NeedSecondRight 置为 false 。最后如果 NeedSecondRight 为 true ,则 res 额外 加一,最后再加上 2*LeftNum 为未匹配的 ‘(’ 补全匹配项。
算法的复杂度:
将字符串扫描一遍字符串,时间复杂度为O(n)。空间复杂度为O(1)。
代码:
class Solution {
public:
int minInsertions(string s) {
int res = 0;
bool NeedSecondRight = false;
int LeftNum = 0;
for(int i = 0; i < s.size(); ++i)
{
if(s[i] == '(')
{
if(NeedSecondRight) //such as the second '(' in "()("
{
++res;
NeedSecondRight = false;
}
++LeftNum;
}
else
{
if(NeedSecondRight) //such as the second ')' in "())"
{
NeedSecondRight = false;
continue;
}
else if(LeftNum == 0) //such as the ')' in ")" {
{
++res;
NeedSecondRight = true;
}
else
{
--LeftNum;
NeedSecondRight = true;
}
}
}
if(NeedSecondRight)
++res;
res += 2* LeftNum;
return res;
}
};