题目1-2为链表的两个基础题
题目3-5为leetcode第308场周赛题目
题目6-9为栈的相关题目
题目10 为二分查找的题目属于复习题。
题目1 力扣
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
vector<int> reversePrint(ListNode* head) {
ListNode* pre=nullptr;
ListNode* cur=head;
while(cur){
ListNode*next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
vector<int>result;
if(pre == nullptr){
return result;
}
while(pre){
result.push_back(pre->val);
pre = pre->next;
}
return result;
}
};
先将链表反转,再递归把数组的值储存进结果数组里。
如果是双向链表,只需要在反转的过程中添加一步:cur->last = next;即可成功的将双向链表反转。
题目2 力扣
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
返回删除后的链表的头节点。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteNode(ListNode* head, int num) {
while(head != nullptr){
if((head->val) != num){
break;
}head = head->next;
}
ListNode* pre = head;
ListNode* cur = head;
while(cur != nullptr){
if(cur->val == num){
pre->next = cur->next;
}else{
pre = cur;
}
cur = cur->next;
}
return head;
}
};
首先遍历一次数组,找到第一个不为目标值的节点,作为返回值待用。
然后命名两个指针,一个指向当前位置,一个指向前一个位置,每当查找到当前指针指向的对应值是要查找的目标值时,就让指向前一个位置的指针直接指向当前位置指针的下一位,就实现了链表中节点值的删除操作。
题目3 力扣 第308场周赛第一题
给你一个长度为 n 的整数数组 nums ,和一个长度为 m 的整数数组 queries 。
返回一个长度为 m 的数组 answer ,其中 answer[i] 是 nums 中 元素之和小于等于 queries[i] 的 子序列 的 最大 长度 。
子序列 是由一个数组删除某些元素(也可以不删除)但不改变剩余元素顺序得到的一个数组。
考虑一种前缀和+二分查找的做法
class Solution {
public:
vector<int> answerQueries(vector<int>& nums, vector<int>& queries) {
sort(nums.begin(),nums.end());
int n =nums.size();
for(int i = 1;i < n; ++i){
nums[i]+=nums[i-1];
}//原数组上进行前缀和操作
vector<int>ans;
for(int q :queries){
int L = 0,R = n-1;
while(L<=R){
int mid = ((R-L)>>1)+L;
if(nums[mid]<=q){
L = mid+1;
}else{
R = mid - 1;
}
}
ans.push_back(L);//查找到之后就压进数组
}
return ans;
}
};
题目4 力扣 第308场周赛第二题
给你一个包含若干星号 * 的字符串 s 。
在一步操作中,你可以:
选中 s 中的一个星号。
移除星号 左侧 最近的那个 非星号 字符,并移除该星号自身。
返回移除 所有 星号之后的字符串。注意:
生成的输入保证总是可以执行题面中描述的操作。
可以证明结果字符串是唯一的。
class Solution {
public:
string removeStars(string s) {
string ans;
for(char c:s){
if(c=='*'){
ans.pop_back();
}else{
ans.push_back(c);
}
}
return ans;
}
};
利用栈的特性。
题目5 力扣 第308场周赛第三题
给你一个下标从 0 开始的字符串数组 garbage ,其中 garbage[i] 表示第 i 个房子的垃圾集合。garbage[i] 只包含字符 'M' ,'P' 和 'G' ,但可能包含多个相同字符,每个字符分别表示一单位的金属、纸和玻璃。垃圾车收拾 一 单位的任何一种垃圾都需要花费 1 分钟。
同时给你一个下标从 0 开始的整数数组 travel ,其中 travel[i] 是垃圾车从房子 i 行驶到房子 i + 1 需要的分钟数。
城市里总共有三辆垃圾车,分别收拾三种垃圾。每辆垃圾车都从房子 0 出发,按顺序 到达每一栋房子。但它们 不是必须 到达所有的房子。
任何时刻只有 一辆 垃圾车处在使用状态。当一辆垃圾车在行驶或者收拾垃圾的时候,另外两辆车 不能 做任何事情。
请你返回收拾完所有垃圾需要花费的 最少 总分钟数。
class Solution {
public:
int garbageCollection(vector<string>& garbage, vector<int>& travel) {
int M=-1,P=-1,G=-1;
for(int i = 0;i<garbage.size();++i){
for(int j = 0; j<garbage[i].size();++j){
if(garbage[i][j] == 'M') M = i;
if(garbage[i][j] == 'P') P = i;
if(garbage[i][j] == 'G') G = i;
}
}
int time = 0;
for(int i = 0;i<garbage.size();++i){
time+=garbage[i].size();
}
for(int i =0;i<M; ++i){
time+=travel[i];
}
for(int i =0;i<P; ++i){
time+=travel[i];
}
for(int i =0;i<G; ++i){
time+=travel[i];
}
return time;
}
};
先找到M,P,G最后出现的位置并标记。然后将两部分时间加合起来即可。
题目6 力扣
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
class Solution {
public:
bool isValid(string s) {
int n = s.size();
if(n%2==1) return false;
unordered_map<char,char>pairs={
{')','('},{']','['},{'}','{'}
};
stack<char>st;
for(char ch :s){
if(pairs.count(ch)){
if(st.empty()||st.top()!=pairs[ch]){
return false;
}
st.pop();
}else{
st.push(ch);
}
}
return st.empty();
}
};
使用哈希表储存有效的符号对,以 ‘]’ ‘ }’ ‘ )’作为key值,在遍历过程中首先检测是左括号还是右括号,左括号直接入栈,如果是右括号检测是否与栈顶元素匹配,匹配则把栈顶元素弹出。
题目7 力扣
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一
class Solution {
public:
string removeDuplicates(string s) {
string stk;
for(char ch:s){
if(!s.empty()&&stk.back() == ch){
stk.pop_back();
}else{
stk.push_back(ch);
}
}
return stk;
}
};
定义一个栈stk,如果栈顶元素与目前遍历到的字符相同,就弹出;否则压栈。
题目8 力扣
给你一个整数数组 nums 。请你对数组执行下述操作:
从 nums 中找出 任意 两个 相邻 的 非互质 数。
如果不存在这样的数,终止 这一过程。
否则,删除这两个数,并 替换 为它们的 最小公倍数(Least Common Multiple,LCM)。
只要还能找出两个相邻的非互质数就继续 重复 这一过程。
返回修改后得到的 最终 数组。可以证明的是,以 任意 顺序替换相邻的非互质数都可以得到相同的结果。生成的测试用例可以保证最终数组中的值 小于或者等于 108 。
两个数字 x 和 y 满足 非互质数 的条件是:GCD(x, y) > 1 ,其中 GCD(x, y) 是 x 和 y 的 最大公约数 。
class Solution {
int GCD(int m, int n){
int z = n;
while (m % n != 0){
z = m % n;
m = n;
n = z;
}
return z;
}
public:
vector<int> replaceNonCoprimes(vector<int>& nums) {
vector<int>ans;
for(int n:nums){
while(!ans.empty()){
int g = GCD(n,ans.back());
if(g>1){
n = n /g * ans.back();
ans.pop_back();
}else{
break;
}
}
ans.push_back(n);
}
return ans;
}
};
定义最大公约数函数GCD,由数学知识我们可以知道GCD乘以最小公倍数LCM等于这两个数的乘积。
之后利用栈的知识 GCD(数组和栈顶元素),如果大于一,就算出LCM,并压栈把栈顶元素弹出。如果不互质就break,最后把这个数压入结果数组中。
题目9 力扣
给你一个下标从 0 开始的整数数组 nums ,如果满足下述条件,则认为数组 nums 是一个 美丽数组 :
nums.length 为偶数
对所有满足 i % 2 == 0 的下标 i ,nums[i] != nums[i + 1] 均成立
注意,空数组同样认为是美丽数组。你可以从 nums 中删除任意数量的元素。当你删除一个元素时,被删除元素右侧的所有元素将会向左移动一个单位以填补空缺,而左侧的元素将会保持 不变 。
返回使 nums 变为美丽数组所需删除的 最少 元素数目。
class Solution {
public:
int minDeletion(vector<int>& nums) {
int n = nums.size();
int flag = 1,last = nums[0],ans = 0;
for(int i = 1;i<n;++i){
if(flag){
if(nums[i] == last){
ans++;
}
else{
flag = 0;
}
}
else{
flag = 1;
last = nums[i];
}
}
return (n - ans)%2 ? ans+1 : ans;
}
};
定义flag用于标识奇偶性,如果是偶数,判断nums[i]与nums[i+1]是否相等如果相等ans+1;
否则继续向下进行。最后判断经过处理后的数组是否为偶数,如果是奇数再进行一步修饰。
题目10 力扣
给定一个排序的整数数组 nums 和一个整数目标值 target ,请在数组中找到 target ,并返回其下标。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int n = nums.size();
int L = 0,R = n - 1;
int mid = 0;
while(L<=R){
mid=L+((R-L)>>1);
if(target <= nums[mid]){
R = mid - 1;
}
else{
L=mid + 1;
}
}
return L;
}
};
使用二分查找 <=targe t的位置即可。