【Leetcode Sheet】Weekly Practice 1

Leetcode Test

822 翻转卡片游戏(8.2)

在桌子上有 n 张卡片,每张卡片的正面和背面都写着一个正数(正面与背面上的数有可能不一样)。

我们可以先翻转任意张卡片,然后选择其中一张卡片。

如果选中的那张卡片背面的数字 x 与任意一张卡片的正面的数字都不同,那么这个数字是我们想要的数字。

哪个数是这些想要的数字中最小的数(找到这些数中的最小值)呢?如果没有一个数字符合要求的,输出 0

其中, fronts[i]backs[i] 分别代表第 i 张卡片的正面和背面的数字。

如果我们通过翻转卡片来交换正面与背面上的数,那么当初在正面的数就变成背面的数,背面的数就变成正面的数。

提示:

  • n == fronts.length == backs.length
  • 1 <= n <= 1000
  • 1 <= fronts[i], backs[i] <= 2000
c 复制代码
int flipgame(int* fronts, int frontsSize, int* backs, int backsSize){
    /*
    如果fronts==backs,则对应的数不可能成为预选
    因为如果i本身正反相等,当前反面已经等于正面
    同时如果backs[i]是其他正反相等里面的数,则一定等于某一个正面值
    否则均可以是预选

    遍历卡片的预选,选择最小的数字,需要考虑正反
    */
    int min=2000;
    bool same[2001];    //hash,标记数值是否可能成为预选
    for(int i=0;i<2001;i++){
        same[i]=0;
    }
    for(int i=0;i<frontsSize;i++){
        if(fronts[i]==backs[i]) same[fronts[i]]=1;  //make a sign,标记数值不可能
    }
    for(int i=0;i<frontsSize;i++){
        if(fronts[i]<min && same[fronts[i]]==0) min=fronts[i];
        if(backs[i]<min && same[backs[i]]==0) min=backs[i];
    }
    return min%2000;
}

722 删除注释(8.3)

给一个 C++ 程序,删除程序中的注释。这个程序source是一个数组,其中source[i]表示第 i 行源码。 这表示每行源码由 '\n' 分隔。

在 C++ 中有两种注释风格,行内注释和块注释。

  • 字符串// 表示行注释,表示//和其右侧的其余字符应该被忽略。
  • 字符串/* 表示一个块注释,它表示直到下一个(非重叠)出现的*/之间的所有字符都应该被忽略。(阅读顺序为从左到右)非重叠是指,字符串/*/并没有结束块注释,因为注释的结尾与开头相重叠。

第一个有效注释优先于其他注释。

  • 如果字符串//出现在块注释中会被忽略。
  • 同样,如果字符串/*出现在行或块注释中也会被忽略。

如果一行在删除注释之后变为空字符串,那么不要输出该行。即,答案列表中的每个字符串都是非空的。

样例中没有控制字符,单引号或双引号字符。

  • 比如,source = "string s = "/* Not a comment. */";" 不会出现在测试样例里。

此外,没有其他内容(如定义或宏)会干扰注释。

我们保证每一个块注释最终都会被闭合, 所以在行或块注释之外的/*总是开始新的注释。

最后,隐式换行符可以通过块注释删除。 有关详细信息,请参阅下面的示例。

从源代码中删除注释后,需要以相同的格式返回源代码。

提示:

  • 1 <= source.length <= 100
  • 0 <= source[i].length <= 80
  • source[i] 由可打印的 ASCII 字符组成。
  • 每个块注释都会被闭合。
  • 给定的源码中不会有单引号、双引号或其他控制字符。
c 复制代码
#define MAX_LINE_LEN 80
//直接遍历,如果有【/*】阻挡就寻找【*/】并设置block,如果有【//】且没有block则忽略当前行的所有内容

char ** removeComments(char ** source, int sourceSize, int* returnSize) {
   char **res = (char **)calloc(sourceSize, sizeof(char *));   //初始化result
   char new_line[sourceSize * MAX_LINE_LEN + 1];   //初始化当前字符串
   int pos = 0, new_line_pos = 0;  //记录数组位置
   bool in_block = false;  //记录是否阻挡
   for (int j = 0; j < sourceSize; j++) {
       char *line = source[j];     //当前行的源代码字符串
       int line_size = strlen(line);   //源代码字符串长度
       for (int i = 0; i < line_size; i++) {
           if (in_block) {     //如果有阻挡
               if (i + 1 < line_size && line[i] == '*' && line[i + 1] == '/') {    //如果【*/】结尾
                   in_block = false;   //取消block
                   i++;    
               }
           } else {    //如果没有阻挡
               if (i + 1 < line_size && line[i] == '/' && line[i + 1] == '*') {    //如果【/*】开头
                   in_block = true;    //重制为有阻挡
                   i++;
               } else if (i + 1 < line_size && line[i] == '/' && line[i + 1] == '/') {     //如果【//】开头
                   break;      //结束当行,因为肯定覆盖了后面所有字符
               } else {    //如果其他字符开头
                   new_line[new_line_pos++] = line[i];     //当前字符计入该行字符串
               }
           }
       }
       if (!in_block && new_line_pos > 0) {    //如果当前字符串非空 且 没有阻挡
           new_line[new_line_pos] = '\0';  //字符串append 【\0】结尾符号
           res[pos] = (char *)calloc(new_line_pos + 1, sizeof(char));  //更新下一行的处理过的代码
           strcpy(res[pos], new_line);     //下一行append 当前字符串
           pos++;  //换行
           new_line_pos = 0;   //初始化当前字符串位置
       }
       *returnSize = pos;  //返回大小为行大小
   }
   return res;
}

980 不同路径Ⅲ(8.4)

在二维网格 grid 上,有 4 种类型的方格:

  • 1 表示起始方格。且只有一个起始方格。
  • 2 表示结束方格,且只有一个结束方格。
  • 0 表示我们可以走过的空方格。
  • -1 表示我们无法跨越的障碍。

返回在四个方向(上、下、左、右)上行走时,从起始方格到结束方格的不同路径的数目**。**

每一个无障碍方格都要通过一次,但是一条路径中不能重复通过同一个方格

提示:

  • 1 <= grid.length * grid[0].length <= 20
c 复制代码
//回溯函数,i和j表示坐标,n表示未访问的【0】坐标数
int dfs(int i,int j,int n,int **grid,int r,int c){
    if(grid[i][j]==2){  //reach termination
        if(n==0) return 1;  //【0】均访问
        else return 0;  //【0】还有剩
    }
    int t=grid[i][j];   //暂存当前坐标的值为t
    int res=0;  //记录是否可能为result
    grid[i][j]=-1;  //当前坐标标记为不可访问
    int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};  //探索当前坐标的上下左右方位情况
    for(int k=0;k<4;k++){
        int ni=i+dir[k][0];     //模拟某一个方位的i坐标
        int nj=j+dir[k][1];     //模拟某一个方位的j坐标
        if(ni>=0 && ni<r && nj>=0 && nj<c && (grid[ni][nj]==0 || grid[ni][nj]==2)){
            res+=dfs(ni,nj,n-1,grid,r,c);   //递归
            //返回某一个方位的新坐标,n-1个剩余【0】坐标,grid坐标
            //r和c有什么用?------r是row numbers,c是column numbers,用于判定边界。
        }
    }
    grid[i][j]=t;   //回复当前坐标的值
    return res;
}

int uniquePathsIII(int** grid, int gridSize, int* gridColSize){
    //每一个无障碍方格都要通过一次,但是一条路径中不能重复通过同一个方格。
    int r=gridSize,c=gridColSize[0];    //initialize row and column numbers
    int si=0,sj=0,n=0;  
        //n用于遍历记录所有【0】坐标个数 + 【1】
        //si是start i,sj是start j,记录起点坐标
    for(int i=0;i<r;i++){
        for(int j=0;j<c;j++){
            if(grid[i][j]==0) n++;
            else if(grid[i][j]==1){
                n++;
                si=i;
                sj=j;
            }
        }
    }   //遍历过程
    return dfs(si,sj,n,grid,r,c);   //回溯法,递归寻找
}

21 合并两个有序链表(8.5)

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

提示:

  • 两个链表的节点数目范围是 [0, 50]
  • -100 <= Node.val <= 100
  • l1l2 均按 非递减顺序 排列
c 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    struct ListNode*l1=list1,*l2=list2;		//rename
    if(l1==NULL) return l2;		//讨论l1和l2为空的情况
    else if(l2==NULL) return l1;
    else if(l1->val <= l2->val){
        //l1 value smaller
        l1->next=mergeTwoLists(l1->next,l2);
        //递归求解l1的下一个节点,把当前下一个节点和l2合并即可
        return l1;
    }
    else{
        //l2 value smaller
        l2->next=mergeTwoLists(l2->next,l1);
        //递归求解l2的下一个节点,把当前下一个节点和l1合并即可
        return l2;
    }
}/*主要用递归继续合并*/
c 复制代码
/*以前的做法*/
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    struct ListNode* tail,* dummyNode;//哨兵
    tail = dummyNode = (struct ListNode*)malloc(sizeof(struct ListNode));
    dummyNode->next = NULL;
    while(list1 && list2){
        if(list1->val < list2->val){
            tail->next = list1;//链接小的节点
            tail = tail->next;//往后更新尾结点
            list1 = list1->next;//往后更新节点
        }
        else{
            tail->next = list2;
            tail = tail->next;
            list2 = list2->next;
        }
    }
    if(list1) tail->next = list1;
    if(list2) tail->next = list2;
    return dummyNode->next;
}

24 两两交换链表中的节点(8.6)

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

提示:

  • 链表中节点的数目在范围 [0, 100]
  • 0 <= Node.val <= 100
c 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* swapPairs(struct ListNode* head){
    if(head==NULL || head->next==NULL){
        //如果头节点是空或者只有一个节点
        return head;
    }
    struct ListNode* newHead=head->next;    //建立新头节点
    head->next=swapPairs(newHead->next);    //对新头节点进行递归swap
    newHead->next=head;     //新头节点的下一个节点连接当前头节点
    return newHead;     //返回新头节点
}

344 反转字符串(8.7)

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

提示:

  • 1 <= s.length <= 105
  • s[i] 都是 ASCII 码表中的可打印字符
c 复制代码
void reverseString(char* s, int sSize){
    int left=0,right=sSize-1;
    while(left<=right){
        char temp=s[left];
        s[left]=s[right];
        s[right]=temp;
        left++;
        right--;
    }
    return s;
}
//双指针 left and right

1749 任意子数组和的绝对值的最大值(8.8)

给你一个整数数组 nums 。一个子数组 [numsl, numsl+1, ..., numsr-1, numsr]和的绝对值abs(numsl + numsl+1 + ... + numsr-1 + numsr)

请你找出 nums和的绝对值 最大的任意子数组(可能为空 ),并返回该 最大值

abs(x) 定义如下:

  • 如果 x 是负整数,那么 abs(x) = -x
  • 如果 x 是非负整数,那么 abs(x) = x

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
c 复制代码
int maxAbsoluteSum(int* nums, int numsSize){
    int pmax=0,nmin=0,psum=0,nsum=0;
    //pmax-positive max number
    //nmin-negative min number
    //psum-positive sum
    //nsum-negative sum
    //psum和nsum用于动态规划
    for(int i=0;i<numsSize;i++){
        psum+=nums[i];  //psum加上当前数字
        pmax=fmax(pmax,psum);   //pmax和psum取最大值
        psum=fmax(0,psum);  //如果psum仍然为正数,则延用
        nsum+=nums[i];  //nsum加上当前数字
        nmin=fmin(nmin,nsum);   //nmin和nsum取最小值
        nsum=fmin(0,nsum);  //如果nsum仍然为负数,则延用
    }
    return fmax(pmax,-nmin);
}

【53 最大子数组和】的变种

c 复制代码
int maxSubArray(int* nums, int numsSize){
    int f=0,max=nums[0];
    for (int i=0;i<numsSize;i++){
        f=fmax(f+nums[i],nums[i]);
        max=fmax(max,f);
    }
    return max;
}
//f用于暂存最大前缀片段和
//max用于暂存最大子数组和

动态转移方程:f(i)=max{ f(i−1)+nums[i] , nums[i]}

前缀片段和的更新:加入nums[i]后,片段和是否变得更大

相关推荐
lsnm8 分钟前
【LINUX网络】IP——网络层
linux·服务器·网络·c++·网络协议·tcp/ip
全糖去冰吃不了苦9 分钟前
ELK 集群部署实战
运维·jenkins
不掰手腕22 分钟前
在UnionTech OS Server 20 (统信UOS服务器版) 上离线安装PostgreSQL (pgsql) 数据库
linux·数据库·postgresql
Lynnxiaowen1 小时前
今天继续昨天的正则表达式进行学习
linux·运维·学习·正则表达式·云计算·bash
努力学习的小廉1 小时前
深入了解linux系统—— POSIX信号量
linux·运维·服务器
刘一说1 小时前
CentOS部署ELK Stack完整指南
linux·elk·centos
从零开始的ops生活1 小时前
【Day 50 】Linux-nginx反向代理与负载均衡
linux·nginx
楠枬1 小时前
ARP 协议
网络·网络协议·arp
IT成长日记1 小时前
【Linux基础】Linux系统配置IP详解:从入门到精通
linux·运维·tcp/ip·ip地址配置
夜无霄1 小时前
安卓逆向(一)Ubuntu环境配置
linux·运维·爬虫·ubuntu