【Leetcode Sheet】Weekly Practice 18

Leetcode Test

1670 设计前中后队列(11.28)

请你设计一个队列,支持在前,中,后三个位置的 pushpop 操作。

请你完成 FrontMiddleBack 类:

  • FrontMiddleBack() 初始化队列。
  • void pushFront(int val)val 添加到队列的 最前面
  • void pushMiddle(int val)val 添加到队列的 正中间
  • void pushBack(int val)val 添加到队里的 最后面
  • int popFront()最前面 的元素从队列中删除并返回值,如果删除之前队列为空,那么返回 -1
  • int popMiddle()正中间 的元素从队列中删除并返回值,如果删除之前队列为空,那么返回 -1
  • int popBack()最后面 的元素从队列中删除并返回值,如果删除之前队列为空,那么返回 -1

请注意当有 两个 中间位置的时候,选择靠前面的位置进行操作。比方说:

  • 6 添加到 [1, 2, 3, 4, 5] 的中间位置,结果数组为 [1, 2, **6**, 3, 4, 5]
  • [1, 2, **3**, 4, 5, 6] 的中间位置弹出元素,返回 3 ,数组变为 [1, 2, 4, 5, 6]

提示:

  • 1 <= val <= 109
  • 最多调用 1000pushFrontpushMiddlepushBackpopFrontpopMiddlepopBack

【双端队列】1670. 设计前中后队列 - 力扣(LeetCode)

cpp 复制代码
class FrontMiddleBackQueue {
    deque<int> left;
    deque<int> right;

    void balance(){
        if(left.size()>right.size()){
            //move the last of left to the head of right
            right.push_front(left.back());
            left.pop_back();
        }
        else if(right.size()>left.size()+1){
            //move the head of right to the last of left
            left.push_back(right.front());
            right.pop_front();
        }
    }
public:
    //初始化
    FrontMiddleBackQueue() {
        //
    }
    //val加到队列最前面
    void pushFront(int val) {
        left.push_front(val);
        balance();
    }
    //val加到队列正中间
    void pushMiddle(int val) {
        if(left.size()<right.size()){
            left.push_back(val);
        }
        else{
            right.push_front(val);
        }
        balance();
    }
    //val加到队列最后面
    void pushBack(int val) {
        right.push_back(val);
        balance();
    }
    //返回最前面的value
    int popFront() {
        if(right.empty()){
            return -1;
        }
        int val;
        if(left.empty()){
            val=right.front();
            right.pop_front();
        }
        else{
            val=left.front();
            left.pop_front();
        }
        balance();
        return val;
    }
    //返回正中间的value
    int popMiddle() {
        if(right.empty()){
            return -1;
        }
        int val;
        if(left.size()==right.size()){
            val=left.back();
            left.pop_back();
        }
        else{
            val=right.front();
            right.pop_front();
        }
        balance();
        return val;
    }
    //返回最后面的value
    int popBack() {
        if(right.empty()){
            return -1;
        }
        int val=right.back();
        right.pop_back();
        balance();
        return val;
    }
};

/**
 * Your FrontMiddleBackQueue object will be instantiated and called as such:
 * FrontMiddleBackQueue* obj = new FrontMiddleBackQueue();
 * obj->pushFront(val);
 * obj->pushMiddle(val);
 * obj->pushBack(val);
 * int param_4 = obj->popFront();
 * int param_5 = obj->popMiddle();
 * int param_6 = obj->popBack();
 */

2336 无限集中的最小数字(11.29)

现有一个包含所有正整数的集合 [1, 2, 3, 4, 5, ...]

实现 SmallestInfiniteSet 类:

  • SmallestInfiniteSet() 初始化 SmallestInfiniteSet 对象以包含 所有 正整数。
  • int popSmallest() 移除 并返回该无限集中的最小整数。
  • void addBack(int num) 如果正整数 num 存在于无限集中,则将一个 num 添加 到该无限集中。

提示:

  • 1 <= num <= 1000
  • 最多调用 popSmallestaddBack 方法 共计 1000

【有序集合】

cpp 复制代码
class SmallestInfiniteSet {
    int thres=1;
    set<int> s;
public:
    //初始化
    SmallestInfiniteSet() { }
    
    //移除 并返回该无限集中的最小整数。
    int popSmallest() {
        //如果比thres小的单独值不存在,则弹出thres
        if(s.empty()){
            int t=thres;
            thres++;
            return t;
        }
        //否则,记录set中的起始值,并弹出
        else{
            int t=*s.begin();
            s.erase(s.begin());
            return t;
        }
    }

    //如果正整数num不存在于infinite,则添加
    void addBack(int num) {
        if(num<thres){
            //如果num小于最小阈值,则添加num,否则表示num一定在阈值后面的集合中
            s.insert(num);
        }
    }
};

/**
 * Your SmallestInfiniteSet object will be instantiated and called as such:
 * SmallestInfiniteSet* obj = new SmallestInfiniteSet();
 * int param_1 = obj->popSmallest();
 * obj->addBack(num);
 */

1657 确定两个字符串是否接近(11.30)

如果可以使用以下操作从一个字符串得到另一个字符串,则认为两个字符串 接近

  • 操作 1:交换任意两个现有字符。

    • 例如,a**b**cd**e** -> a**e**cd**b**
  • 操作 2:将一个现有字符的每次出现转换为另一个现有字符,并对另一个字符执行相同的操作。

    • 例如,**aa**c**abb** -> **bb**c**baa**(所有 a 转化为 b ,而所有的 b 转换为 a

你可以根据需要对任意一个字符串多次使用这两种操作。

给你两个字符串,word1word2 。如果 word1word2 接近 ,就返回 true ;否则,返回 false

提示:

  • 1 <= word1.length, word2.length <= 105
  • word1word2 仅包含小写英文字母

【hash】

c 复制代码
int cmp(void *a,void *b){
    return *(int*)a-*(int*)b;
}

bool closeStrings(char* word1, char* word2) {
    int n1=strlen(word1),n2=strlen(word2);
    if(n1!=n2) return 0;

    int *hash1=(int*)malloc(sizeof(int)*26);
    int *hash2=(int*)malloc(sizeof(int)*26);
    for(int i=0;i<26;i++){
        hash1[i]=0;
    }
    for(int i=0;i<26;i++){
        hash2[i]=0;
    }

    //hash counting
    for(int i=0;i<n1;i++){
        hash1[word1[i]-'a']++;
    }
    for(int i=0;i<n2;i++){
        hash2[word2[i]-'a']++;
    }

    //existing words judge
    for(int i=0;i<26;i++){
        if(hash1[i]!=0 && hash2[i]==0){
            return 0;
        }
        else if(hash1[i]==0 && hash2[i]!=0){
            return 0;
        }
    }

    //sort array
    qsort(hash1,26,sizeof(int),cmp);
    qsort(hash2,26,sizeof(int),cmp);

    //compare
    for(int i=0;i<26;i++){
        if(hash1[i]!=hash2[i]){
            return 0;
        }
    }
    return 1;
}

2661 找出叠涂元素(12.1)

给你一个下标从 0 开始的整数数组 arr 和一个 m x n 的整数 矩阵 matarrmat 都包含范围 [1,m * n] 内的 所有 整数。

从下标 0 开始遍历 arr 中的每个下标 i ,并将包含整数 arr[i]mat 单元格涂色。

请你找出 arr 中在 mat 的某一行或某一列上都被涂色且下标最小的元素,并返回其下标 i

提示:

  • m == mat.length
  • n = mat[i].length
  • arr.length == m * n
  • 1 <= m, n <= 105
  • 1 <= m * n <= 105
  • 1 <= arr[i], mat[r][c] <= m * n
  • arr 中的所有整数 互不相同
  • mat 中的所有整数 互不相同

【hash counting】

c 复制代码
int firstCompleteIndex(int* arr, int arrSize, int** mat, int matSize, int* matColSize){
    int len=arrSize,m=matSize,n=matColSize[0];
    int *row=(int*)malloc(sizeof(int)*(len+1));
    int *col=(int*)malloc(sizeof(int)*(len+1));
    //record the row and col of each figure
    for(int i=0;i<len+1;i++){
        row[i]=-1;
        col[i]=-1;
    }
    int *checkrow=(int*)malloc(sizeof(int)*m);
    int *checkcol=(int*)malloc(sizeof(int)*n);
    for(int i=0;i<m;i++){
        checkrow[i]=n;
    }
    for(int i=0;i<n;i++){
        checkcol[i]=m;
    }
    //每行有n个数,每列有m个数

    //hash record the row&col of each figure
    for(int i=0;i<m;i++){
        for(int j=0;j<n;j++){
            int fig=mat[i][j];
            row[fig]=i;
            col[fig]=j;
        }
    }

    int ret=-1;
    for(int i=0;i<len;i++){
        int temp=arr[i];
        //temp's position should add to hash
        int temprow=row[temp];
        int tempcol=col[temp];
        checkrow[temprow]--;
        checkcol[tempcol]--;
        if(checkrow[temprow]==0 || checkcol[tempcol]==0){
            ret=i;
            break;
        }
    }
    return ret;
}

1094 拼车(12.2)

车上最初有 capacity 个空座位。车 只能 向一个方向行驶(也就是说,不允许掉头或改变方向

给定整数 capacity 和一个数组 trips , trip[i] = [numPassengersi, fromi, toi] 表示第 i 次旅行有 numPassengersi 乘客,接他们和放他们的位置分别是 fromitoi 。这些位置是从汽车的初始位置向东的公里数。

当且仅当你可以在所有给定的行程中接送所有乘客时,返回 true,否则请返回 false

提示:

  • 1 <= trips.length <= 1000
  • trips[i].length == 3
  • 1 <= numPassengersi <= 100
  • 0 <= fromi < toi <= 1000
  • 1 <= capacity <= 105

【hash计数】

c 复制代码
bool carPooling(int** trips, int tripsSize, int* tripsColSize, int capacity) {
    //capacity个空座位
    //trips[i] 0:旅客数量 1:上车位置 2:下车位置
    int *check=(int*)malloc(sizeof(int)*1001);
    for(int i=0;i<1001;i++){
        check[i]=0;
    }
    bool flag=1;
    for(int i=0;i<tripsSize;i++){
        int start=trips[i][1];
        int end=trips[i][2];
        int num=trips[i][0];
        while(start<end){
            check[start]+=num;
            if(check[start]>capacity){
                flag=0;
                break;
            }
            start++;
        }
        if(flag==0){
            break;
        }
    }
    return flag;
}

【差分】1094. 拼车 - 力扣(LeetCode)

c 复制代码
bool carPooling(int **trips, int tripsSize, int *tripsColSize, int capacity) {
    //找到最大的time,为开辟数组做准备
    int toMax = 0;
    for (int i = 0; i < tripsSize; i++) {
        if (toMax < trips[i][2]) {
            toMax = trips[i][2];
        }
    }
	//开辟数组,并初始化diff的值
    int *diff = malloc(sizeof(int) * (toMax + 1));
    memset(diff, 0, sizeof(int) * (toMax + 1));
    for (int i = 0; i < tripsSize; i++) {
        diff[trips[i][1]] += trips[i][0];
        diff[trips[i][2]] -= trips[i][0];
    }

    int count = 0;
    for (int i = 0; i < toMax; i++) {
        count += diff[i];
        if (count > capacity) {
            return false;
        }
    }
    free(diff);
    return true;
}

1423 可获得的最大点数(12.3)

几张卡牌 排成一行 ,每张卡牌都有一个对应的点数。点数由整数数组 cardPoints 给出。

每次行动,你可以从行的开头或者末尾拿一张卡牌,最终你必须正好拿 k 张卡牌。

你的点数就是你拿到手中的所有卡牌的点数之和。

给你一个整数数组 cardPoints 和整数 k,请你返回可以获得的最大点数。

提示:

  • 1 <= cardPoints.length <= 10^5
  • 1 <= cardPoints[i] <= 10^4
  • 1 <= k <= cardPoints.length

【滑动窗口】滑动不需要的格子(总量 - 不需要的)

c 复制代码
int maxScore(int* cardPoints, int cardPointsSize, int k) {
    int n=cardPointsSize,sum=0,window=n-k;
    //初始化,取最左侧的k个数字作为窗口的sum
    for(int i=0;i<window;i++){
        sum+=cardPoints[i];
    }

    int temp=sum,minsum=sum;
    for(int i=window;i<n;i++){
        //增加一个右侧的值,减去一个左侧的值
        sum+=cardPoints[i]-cardPoints[i-window];
        minsum=fmin(minsum,sum);
        temp+=cardPoints[i];
    }
    return temp-minsum;
}

【滑动窗口】滑动需要的格子(直接计算需要的)

c 复制代码
int maxScore(int* cardPoints, int cardPointsSize, int k) {
    //start or end, pick a card, total = k
    int n=cardPointsSize,maxsum=0;
    //初始化,滑左侧k个
    for(int i=0;i<k;i++){
        maxsum+=cardPoints[i];
    }
    //每次从右侧滑动最末尾的一个进来,然后从左侧弹出一个走
    int newsum=maxsum;
    for(int i=0;i<k;i++){
        newsum+=cardPoints[n-i-1];
        newsum-=cardPoints[k-i-1];
        maxsum=fmax(maxsum,newsum);
    }

    return maxsum;
}

1038 从二叉搜索树到更大和树(12.4)

给定一个二叉搜索树 root (BST),请将它的每个节点的值替换成树中大于或者等于该节点值的所有节点值之和。

提醒一下, 二叉搜索树 满足下列约束条件:

  • 节点的左子树仅包含键 小于 节点键的节点。
  • 节点的右子树仅包含键 大于 节点键的节点。
  • 左右子树也必须是二叉搜索树。

提示:

  • 树中的节点数在 [1, 100] 范围内。
  • 0 <= Node.val <= 100
  • 树中的所有值均 不重复

**注意:**该题目与 538: https://leetcode-cn.com/problems/convert-bst-to-greater-tree/相同

【反序中序遍历】

c 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
int sum;

struct TreeNode* dfs(struct TreeNode* root){
    if(root){
        dfs(root->right);
        sum+=root->val;
        root->val=sum;
        dfs(root->left);
    }
    return root;
}

struct TreeNode* bstToGst(struct TreeNode* root) {
    sum=0;
    dfs(root);
    return root;
}

【Morris遍历】

c 复制代码
struct TreeNode* getSuccessor(struct TreeNode* node) {
    struct TreeNode* succ = node->right;
    while (succ->left != NULL && succ->left != node) {
        succ = succ->left;
    }
    return succ;
}

struct TreeNode* bstToGst(struct TreeNode* root) {
    int sum = 0;
    struct TreeNode* node = root;

    while (node != NULL) {
        if (node->right == NULL) {
            sum += node->val;
            node->val = sum;
            node = node->left;
        } else {
            struct TreeNode* succ = getSuccessor(node);
            if (succ->left == NULL) {
                succ->left = node;
                node = node->right;
            } else {
                succ->left = NULL;
                sum += node->val;
                node->val = sum;
                node = node->left;
            }
        }
    }

    return root;
}
相关推荐
xiaoshiguang34 小时前
LeetCode:222.完全二叉树节点的数量
算法·leetcode
爱吃西瓜的小菜鸡4 小时前
【C语言】判断回文
c语言·学习·算法
别NULL4 小时前
机试题——疯长的草
数据结构·c++·算法
TT哇4 小时前
*【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
java·算法·蓝桥杯
yuanbenshidiaos5 小时前
C++----------函数的调用机制
java·c++·算法
唐叔在学习5 小时前
【唐叔学算法】第21天:超越比较-计数排序、桶排序与基数排序的Java实践及性能剖析
数据结构·算法·排序算法
ALISHENGYA6 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(switch语句)
数据结构·算法
chengooooooo6 小时前
代码随想录训练营第二十七天| 贪心理论基础 455.分发饼干 376. 摆动序列 53. 最大子序和
算法·leetcode·职场和发展
jackiendsc6 小时前
Java的垃圾回收机制介绍、工作原理、算法及分析调优
java·开发语言·算法
姚先生976 小时前
LeetCode 54. 螺旋矩阵 (C++实现)
c++·leetcode·矩阵