第一题
给你一个正整数 n ,找出满足下述条件的 中枢整数 x :
1 和 x 之间的所有元素之和等于 x 和 n 之间所有元素之和。
返回中枢整数 x 。如果不存在中枢整数,则返回 -1 。题目保证对于给定的输入,至多存在一个中枢整数。
示例 1:
输入:n = 8
输出:6
解释:6 是中枢整数,因为 1 + 2 + 3 + 4 + 5 + 6 = 6 + 7 + 8 = 21 。
示例 2:
输入:n = 1
输出:1
解释:1 是中枢整数,因为 1 = 1 。
示例 3:
输入:n = 4
输出:-1
解释:可以证明不存在满足题目要求的整数。
提示:
1 <= n <= 1000
分析:
我们需要判断是否存在一个在1~n中的数,使得1 + 2 + 3 + … +i
i + (i + 1) + (i + 2) + … +n相等。由于数据范围只有1000,所以可以直接利用求和公式暴力求解。时间复杂度O(N)。
代码
class Solution {
public:
int pivotInteger(int n) {
int ans = -1;
for(int i = 1;i <= n;i++){
int a = (i+1)*i/2;
int b = (i + n)*(n-i+1)/2;
if(a == b){
ans = i;
break;
}
}
return ans;
}
};
第二题
给你两个仅由小写英文字母组成的字符串 s 和 t 。
现在需要通过向 s 末尾追加字符的方式使 t 变成 s 的一个 子序列 ,返回需要追加的最少字符数。
子序列是一个可以由其他字符串删除部分(或不删除)字符但不改变剩下字符顺序得到的字符串。
示例 1:
输入:s = “coaching”, t = “coding”
输出:4
解释:向 s 末尾追加字符串 “ding” ,s =“coachingding” 。 现在t是(“coachingding”) 的一个子序列。 可以证明向 s 末尾追加任何 3个字符都无法使 t 成为 s 的一个子序列。
示例 2:
输入:s = “abcde”, t = “a”
输出:0
解释:t 已经是 s (“abcde”) 的一个子序列。
示例 3:
输入:s = “z”, t = “abcde”
输出:5
解释:向 s 末尾追加字符串 “abcde” ,s = “zabcde” 。
现在,t 是 s (“zabcde”) 的一个子序列。 可以证明向 s 末尾追加任何 4 个字符都无法使 t 成为 s 的一个子序列。
提示:
1 <= s.length, t.length <= 105
s 和 t 仅由小写英文字母组成
分析:
我们先让s 和 t进行匹配,当 s 中没有能与 t中字符相匹配的字符时,此时 t 剩余的还没匹配的字符数量就是答案。时间复杂度O(N)
代码:
class Solution {
public:
int appendCharacters(string s, string t) {
int m = s.size(),n = t.size();
int j = 0;
for(int i = 0;i < m;i++){
//成功匹配则 j 往后移
if(j < n && s[i] == t[j]) j++;
//当此时已经完全匹配,就提前退出循环
if(j == n) break;
}
//此时的 n - j 就是t剩下的还没被匹配的字符数量
return n - j;
}
};
第三题
给你一个链表的头节点 head 。
对于列表中的每个节点 node ,如果其右侧存在一个具有 严格更大 值的节点,则移除 node 。
返回修改后链表的头节点 head 。
示例 1:
输入:head = [5,2,13,3,8]
输出:[13,8]
解释:需要移除的节点是 5 ,2 和 3 。
- 节点 13 在节点 5 右侧。
- 节点 13 在节点 2 右侧。
- 节点 8 在节点 3 右侧。
示例 2:
输入:head = [1,1,1,1]
输出:[1,1,1,1]
解释:每个节点的值都是 1 ,所以没有需要移除的节点。
提示:
给定列表中的节点数目在范围 [1, 1 0 5 10^5 105] 内
1 <= Node.val <= 1 0 5 10^5 105
分析:
按照题目的规则,我们只要在纸上简单的模拟一些就可以得出结论:剩下的一条链表肯定是一条单调不增的链表
例如:[5,2,13,3,13,7,12,8,9,12]
最终的结果为:[13,13,12,12]
所以我们只需要先将答案的结点先求出来,然后再将这些答案结点连起来就好了。
代码:
class Solution {
public:
ListNode* removeNodes(ListNode* head) {
//用vector模拟单调栈
vector<int> q;
ListNode* cur = head;
while(cur){
//将q中 小于 cur->val 的元素全部弹出去
//例如:此时q 中的元素为 9 , 5 , 2 ,2
//此时的cur->val = 6;
//经过如下操作 q 中只剩 9 一个元素了
while(!q.empty() && cur->val > q.back()) q.pop_back();
q.push_back(cur->val);
cur = cur->next;
}
int i = 0;
//定义哨兵结点
ListNode* dummy = new ListNode(-1);
//定义指向cur结点的前一个结点的指针
ListNode* pre = dummy;
cur = head;
while(cur){
//如果当前值 等于 答案数组里的值 就进行操作
if(cur->val == q[i]){
pre->next = cur;
pre = cur;
i++;
}
cur = cur->next;
}
return dummy->next;
}
};
第四题
给你一个长度为 n 的数组 nums ,该数组由从 1 到 n 的 不同 整数组成。另给你一个正整数 k 。
统计并返回 num 中的 中位数 等于 k 的非空子数组的数目。
注意:
数组的中位数是按 递增 顺序排列后位于 中间 的那个元素,如果数组长度为偶数,则中位数是位于中间靠 左 的那个元素。
例如,[2,3,1,4] 的中位数是 2 ,[8,4,3,5,1] 的中位数是 4 。 子数组是数组中的一个连续部分。
示例 1:
输入:nums = [3,2,1,4,5], k = 4
输出:3
解释:中位数等于 4 的子数组有:[4]、[4,5] 和 [1,4,5]。
示例 2:
输入:nums = [2,3,1], k = 3
输出:1
解释:[3] 是唯一一个中位数等于 3 的子数组。
提示:
n == nums.length
1 <= n <= 1 0 5 10^5 105
1 <= nums[i], k <= n
nums 中的整数互不相同
分析:
给定的数组包含1~n,共n个不同的元素,并且k <= n,所以k是肯定存在数组中的。
按照题目要求 求子数组的中位数为k 的数量
我们可以将其这样转化:
让 大于 k的数变为 1,小于k的数变为-1,等于k的数是0。这样我们就只需要求能让子数组的和为 0 或者 为 1 的数量就好了
子数组的和为1:是因为题目要求,当子数组数量是偶数时,中位数是靠左边的那个数。
第一步是先找到中位数k在数组中的位置 pos
接着就是分别枚举0 ~ pos-1,pos + 1 ~ n的情况,我们需要开一个哈希表来记录个数
代码:
class Solution {
public:
int countSubarrays(vector<int>& nums, int k) {
int n = nums.size();
int pos = 0;
//寻找中位数在数组中的位置pos
for(int i = 0;i < n;i++){
if(nums[i] == k){
pos = i;
break;
}
}
//记录个数
unordered_map<int,int> cnt;
//k本身也算作一个答案
cnt[0] = 1;
int sum = 0;
//从pos左边枚举到开始的位置
for(int i = pos-1;i >= 0;i--){
if(nums[i] > k) sum++;
else sum--;
//记录pos左边的情况
cnt[sum]++;
}
//先加上左边的结果
int ans = cnt[0] + cnt[1];
sum = 0;
//枚举pos右边到n的情况
for(int i = pos + 1;i < n;i++){
if(nums[i] > k) sum++;
else sum--;
//如果cnt 存在元素 使得其 + sum = 0 或者是 1 那么就加入到结果里面
ans += cnt[-1*sum];
ans += cnt[1-sum];
}
return ans;
}
};