刷题记录5

题目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的位置即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值