LeetCode题库-11~20(C语言)

11 盛最多水的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0)(i, height[i])
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明: 你不能倾斜容器。

  1. 示例1
    在这里插入图片描述
    • 输入: [1,8,6,2,5,4,8,3,7]
    • 输出: 49
    • 解释: 图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
  2. 示例2
    • 输入: height = [1,1]
    • 输出: 1
  3. 提示:

n == height.length
2 <= n <= 105
0 <= height[i] <= 104

代码:

int maxArea(int* height, int heightSize)
{
    int left = 0;               //数组左侧指针
    int right = heightSize - 1; //数组右侧指针
    int maxArea = 0;            //初始化最大容量
    while (left < right)        //左右指针不重叠不交换
    {
        int wide = right - left;                      //宽
        int high = fmin(height[left], height[right]); //高,高度更小的
        int area = wide * high;                       //面积=宽*高
        if (area > maxArea)                           //更新最大容量
            maxArea = area;
        if (height[left] < height[right]) //从左向右遍历
            left++;
        else //从右向左遍历
            right--;
    }
    return maxArea;
}

12 整数转罗马数字

罗马数字包含以下七种字符: IVXLCDM

字符数值
I1
V5
X10
L50
C100
D500
M1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

  • I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
  • X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
  • C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。

给你一个整数,将其转为罗马数字。

  1. 示例1
    • 输入: num = 3
    • 输出: “III”
  2. 示例2
    • 输入: num = 4
    • 输出: “IV”
  3. 示例3
    • 输入: num = 9
    • 输出: “IX”
  4. 示例4
    • 输入: num = 58
    • 输出: “LVIII”
    • 解释: L = 50, V = 5, III = 3.
  5. 示例5
    • 输入: num = 1994
    • 输出: “MCMXCIV”
    • 解释: M = 1000, CM = 900, XC = 90, IV = 4.
  6. 提示:

1 <= num <= 3999

代码:

//符号和数值对应表
const int value[] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
const char* symbol[] = {"M",  "CM", "D",  "CD", "C",  "XC", "L",
                        "XL", "X",  "IX", "V",  "IV", "I"};
char* intToRoman(int num)
{
    char* roman = malloc(sizeof(char) * 16); //申请内存
    roman[0] = '\0';                         //字符数组初始化
    for (int i = 0; i < 13; i++)
    {
        while (num >= value[i])
        {
            num -= value[i];
            strcpy(roman + strlen(roman), symbol[i]);
            //把符号表中对应数值的符号复制到roman中
            //在roman数组中符号之间不覆盖、向后排列
        }
        if (num == 0)
            break;
    }
    return roman;
}

13 罗马数字转整数

罗马数字包含以下七种字符: IVXLCDM

字符数值
I1
V5
X10
L50
C100
D500
M1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

  • I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
  • X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
  • C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。

给你一个罗马数字,将其转为整数。

  1. 示例1
    • 输入: s = “III”
    • 输出: 3
  2. 示例2
    • 输入: s = “IV”
    • 输出: 4
  3. 示例3
    • 输入: s = “IX”
    • 输出: 9
  4. 示例4
    • 输入: s = “LVIII”
    • 输出: 58
    • 解释: L = 50, V = 5, III = 3.
  5. 示例5
    • 输入: s = “MCMXCIX”
    • 输出: 1994
    • 解释: M = 1000, CM = 900, XC = 90, IV = 4.
  6. 提示:

1 <= s.length <= 15
s 仅含字符 (‘I’, ‘V’, ‘X’, ‘L’, ‘C’, ‘D’, ‘M’)
题目数据保证 s 是一个有效的罗马数字,且表示整数在范围 [1, 3999] 内
题目所给测试用例皆符合罗马数字书写规则,不会出现跨位等情况。
IL 和 IM 这样的例子并不符合题目要求,49 应该写作 XLIX,999 应该写作 CMXCIX 。
关于罗马数字的详尽书写规则,可以参考 罗马数字 - Mathematics 。

代码:

int romanToInt(char* s)
{
    int num = 0;
    while (*s) //分情况讨论,V、L、D、M 或 I、X、C
    {
        if (*s == 'V')
            num += 5;
        else if (*s == 'L')
            num += 50;
        else if (*s == 'D')
            num += 500;
        else if (*s == 'M')
            num += 1000;
        else if (*s == 'I') // I的下一位为V或X,则减一;否则,加一。
            num = (*(s + 1) == 'V' || *(s + 1) == 'X') ? num - 1 : num + 1;
        else if (*s == 'X') // X的下一位为L或C,则减十;否则,加十。
            num = (*(s + 1) == 'L' || *(s + 1) == 'C') ? num - 10 : num + 10;
        else // C的下一位为D或M,则减一百;否则,加一百。
            num = (*(s + 1) == 'D' || *(s + 1) == 'M') ? num - 100 : num + 100;
        s++; //顺位依次判断
    }
    return num;
}

14 最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”

  1. 示例1
    • 输入: strs = [“flower”,“flow”,“flight”]
    • 输出: “fl”
  2. 示例2
    • 输入: strs = [“dog”,“racecar”,“car”]
    • 输出: “”
    • 解释: 输入不存在公共前缀。
  3. 提示:

1 <= strs.length <= 200
0 <= strs[i].length <= 200
strs[i] 仅由小写英文字母组成

代码:

char* longestCommonPrefix(char** strs, int strsSize)
{
    if (strsSize == 0) //字符串为空,直接返回
        return "";
    for (int i = 0; i < strsSize; i++) //分为i行
    {
        for (int j = 0; j < strlen(strs[0]); j++) //分为j列
        {
            if (strs[0][j] != strs[i][j]) //某一列上字符不相同
            {
                strs[0][j] = '\0'; //结束字符
                break;
            }
        }
    }
    return strs[0];
}

15 三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != kj != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0
请你返回所有和为 0 且不重复的三元组。
注意: 答案中不可以包含重复的三元组。

  1. 示例1
    • 输入: nums = [-1,0,1,2,-1,-4]
    • 输出: [[-1,-1,2],[-1,0,1]]
    • 解释:
      nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
      nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
      nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
      不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
      注意,输出的顺序和三元组的顺序并不重要。
  2. 示例2
    • 输入: nums = [0,1,1]
    • 输出: [ ]
    • 解释: 唯一可能的三元组和不为 0 。
  3. 示例3
    • 输入: nums = [0,0,0]
    • 输出: [[0,0,0]]
    • 解释: 唯一可能的三元组和为 0 。
  4. 提示:

3 <= nums.length <= 3000
-105 <= nums[i] <= 105

代码:

/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume
 * caller calls free().
 */
int cmp(const void* a, const void* b) //排序规则
{
    return *(int*)a - *(int*)b; //升序(ab换位,即降序)
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes)
{
    *returnSize = 0;  //初始化返回值
    if (numsSize < 3) //无法构成三元组
        return NULL;
    // qsort函数——数组排序
    //数组名、元素个数、数组元素所占字节、排序原则(升序)
    qsort(nums, numsSize, sizeof(int), cmp);
    int** ret = (int**)malloc(sizeof(int*) * numsSize * numsSize); //申请内存
    *returnColumnSizes = (int*)malloc(sizeof(int) * numsSize * numsSize); //申请内存
    int i = 0, j = 0, k = 0;                             //三指针遍历
    for (i = 0; i < numsSize; i++)
    {
        if (i > 0 && nums[i] == nums[i - 1]) //值相同,不需遍历
            continue;
        j = i + 1;
        k = numsSize - 1;
        while (j < k) //双指针遍历
        {
            int sum = nums[i] + nums[j] + nums[k];
            if (sum == 0) //三元组
            {
                ret[*returnSize] = (int*)malloc(sizeof(int) * 3); //申请空间
                (*returnColumnSizes)[*returnSize] = 3; //每一个数组大小为3
                //给申请的空间赋值
                ret[*returnSize][0] = nums[i];
                ret[*returnSize][1] = nums[j];
                ret[*returnSize][2] = nums[k];
                *returnSize += 1;
                while (j < k && nums[j] == nums[++j]); //去重
                while (j < k && nums[k] == nums[--k]); //去重
            }
            else if (sum > 0) //三数之和大于0,左边递减
                k--;
            else //三数之和小于0,右边递增
                j++;
        }
    }
    return ret;
}

16 最接近的三数之和

给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。
返回这三个数的和。
假定每组输入只存在恰好一个解。

  1. 示例1
    • 输入: nums = [-1,2,1,-4], target = 1
    • 输出: 2
    • 解释: 与 target 最接近的和是 2 (-1 + 2 + 1 = 2)
  2. 示例2
    • 输入: nums = [0,0,0], target = 1
    • 输出: 0
  3. 提示:

3 <= nums.length <= 1000
-1000 <= nums[i] <= 1000
-104 <= target <= 104

代码:

int cmp(const void* a, const void* b) //排序规则
{
    return *(int*)a - *(int*)b; //升序(ab换位,即降序)
}
int threeSumClosest(int* nums, int numsSize, int target)
{
    // qsort函数——数组排序
    //数组名、元素个数、数组元素所占字节、排序原则(升序)
    qsort(nums, numsSize, sizeof(int), cmp);
    int min_sum = nums[0] + nums[1] + nums[2]; //最小三数之和
    for (int i = 0; i < numsSize; i++)
    {
        for (int j = i + 1; j < numsSize; j++) 
        {
            for (int k = j + 1; k < numsSize; k++)
            {
                int sum = nums[i] + nums[j] + nums[k]; //三数之和
                int min_dif = min_sum - target;        //最小差值
                int dif = sum - target;                //差值
                if (min_dif < 0)                       //取正值
                    min_dif = target - min_sum;
                if (dif < 0) //取正值
                    dif = target - sum;
                if (dif < min_dif) //更新最小和
                    min_sum = sum;
            }
        }
    }
    return min_sum;
}

17 电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
在这里插入图片描述

  1. 示例1
    • 输入: digits = “23”
    • 输出: [“ad”,“ae”,“af”,“bd”,“be”,“bf”,“cd”,“ce”,“cf”]
  2. 示例2
    • 输入: digits = “”
    • 输出: []
  3. 示例3
    • 输入: digits = “2”
    • 输出: [“a”,“b”,“c”]
  4. 提示:

0 <= digits.length <= 4
digits[i] 是范围 [‘2’, ‘9’] 的一个数字。

代码:

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
char letter[10][5] = {"\0",    "\0",    "abc\0",  "def\0", "ghi\0",
                      "jkl\0", "mno\0", "pqrs\0", "tuv\0", "wxyz\0"};
char** letterCombinations(char* digits, int* returnSize)
{
    int length = strlen(digits);       //字母长度=数字数量
    if (digits == NULL || length == 0) //空
    {
        *returnSize = 0;
        return NULL;
    }
    int letterSize = pow(4, length + 1); //字母组合总数的最大量
    char** que = (char**)malloc(sizeof(char*) * letterSize); //辅助队列
    for (int i = 0; i < letterSize; i++) //为辅助队列申请空间并初始化为0
    {
        que[i] = (char*)calloc(length + 1, sizeof(char));
    }
    int front = 0, rear = 0;
    que[rear++] = '\0'; //把空串作为队列的第一个节点
    for (int i = 0; i < length; i++)
    {
        int queSize = rear - front; //当前队列长度
        for (int j = 0; j < queSize; j++)
        {
            for (int k = 0; k < strlen(letter[digits[i] - '0']); k++)
            {
                char temp[10];
                memset(temp, 0, 10); //初始化,tmp前10个字节的内存单元用0替换
                if (que[front] != NULL)
                {
                    strcpy(temp, que[front]); //把先前出队的字符复制到tmp中
                }
                int t = strlen(temp);
                temp[t] = letter[digits[i] - '0'][k]; //找到下一个数字对应的字母
                strcpy(que[rear++], temp);            //把字母紧接着入队
            }
            front++;
        }
    }
    *returnSize = rear - front;
    return que + front; //输出结果
}

18 四数之和

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

  • 0 <= a, b, c, d < n
  • a、b、c 和 d 互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target

你可以按 任意顺序 返回答案。

  1. 示例1
    • 输入: nums = [1,0,-1,0,-2,2], target = 0
    • 输出: [[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
  2. 示例2
    • 输入: nums = [2,2,2,2,2], target = 8
    • 输出: [[2,2,2,2]]
  3. 提示:

1 <= nums.length <= 200
-109 <= nums[i] <= 109
-109 <= target <= 109

代码:

/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume
 * caller calls free().
 */
int cmp(const void* a, const void* b) //排序规则
{
    return *(int*)a - *(int*)b; //升序(ab换位,即降序)
}
int** fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes)
{
    *returnSize = 0;  //初始化返回值
    if (numsSize < 4) //无法构成四元组
        return NULL;
    int** ret = (int**)malloc(sizeof(int*) * (numsSize + 1) * 3); //申请内存
    *returnColumnSizes = malloc(sizeof(int) * (numsSize + 1) * 3); //申请内存
    // qsort函数——数组排序
    //数组名、元素个数、数组元素所占字节、排序原则(升序)
    qsort(nums, numsSize, sizeof(int), cmp);
    int a, b, c, d;
    long long sum = 0;
    int left = 0;                      //用来遍历的左指针
    int right = 0;                     //用来遍历的右指针
    for (a = 0; a < numsSize - 3; a++) // a、b、c、d占四个位置
    {
        if ((nums[a] > 0) && (nums[a] > target)) //剪枝,
            break;
        if (a > 0 && nums[a] == nums[a - 1]) //去重
            continue;
        for (b = a + 1; b < numsSize; b++) //双指针遍历
        {
            if ((b > a + 1) && (nums[b] == nums[b - 1])) //去重
                continue;
            if (((nums[a] + nums[b]) > target) && (nums[b] > 0)) //剪枝
                break;
            left = b + 1;
            right = numsSize - 1;
            while (left < right)
            {
                sum = (long)nums[a] + nums[b] + nums[left] + nums[right];
                if (sum == target) {
                    ret[*returnSize] = malloc(sizeof(int) * 4); //申请空间
                    (*returnColumnSizes)[*returnSize] = 4; //每一个数组大小为4
                    ret[*returnSize][0] = nums[a]; //给申请的空间赋值
                    ret[*returnSize][1] = nums[b];
                    ret[*returnSize][2] = nums[left];
                    ret[*returnSize][3] = nums[right];
                    (*returnSize)++;
                    //跳过相同的值
                    while ((left < right) && nums[left] == nums[left+1])
                        left++;
                    while ((left < right) && nums[right] == nums[right-1])
                        right--;
                    left++;
                    right--;
                }
                else if (sum < target)
                    left++;
                else if (sum > target)
                    right--;
            }
        }
    }
    return ret;
}

19 删除链表的倒数第N个结点

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

  1. 示例1
    在这里插入图片描述
    • 输入: head = [1,2,3,4,5], n = 2
    • 输出: [1,2,3,5]
  2. 示例2
    • 输入: head = [1], n = 1
    • 输出: []
  3. 示例3
    • 输入: head = [1,2], n = 1
    • 输出: [1]
  4. 提示:

链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz

代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
int length(struct ListNode* head) //计算链表长度
{
    int len = 0;
    while (head)
    {
        ++len;
        head = head->next;
    }
    return len;
}
struct ListNode* removeNthFromEnd(struct ListNode* head, int n)
{
    struct ListNode* list = malloc(sizeof(struct ListNode)); //为链表申请空间
    list->val = 0, list->next = head;
    int len = length(head); //计算长度
    struct ListNode* new = list;
    for (int i = 1; i < len - n + 1; ++i) //在要删除的节点前,正常遍历
        new = new->next;
    new->next = new->next->next; //在要删除的节点处,修改指针,跳过该节点
    struct ListNode* ret = list->next; //最终存储到ret中
    free(list);
    return ret;
}

20 有效的括号

给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:

  • 左括号必须用相同类型的右括号闭合。
  • 左括号必须以正确的顺序闭合。
  • 每个右括号都有一个对应的相同类型的左括号。
  1. 示例1
    • 输入: s = “()”
    • 输出: true
  2. 示例2
    • 输入: s = “()[]{}”
    • 输出: true
  3. 示例3
    • 输入: s = “(]”
    • 输出: false
  4. 提示:

1 <= s.length <= 104
s 仅由括号 ‘()[]{}’ 组成

代码:

char pairs(char a) //括号对
{
    if (a == '}')
        return '{';
    if (a == ']')
        return '[';
    if (a == ')')
        return '(';
    return 0;
}
bool isValid(char* s)
{
    int n = strlen(s); //字符串长度
    if (n % 2 == 1)    //字符串长度为奇数,无法匹配
        return false;
    int stack[n + 1], top = 0;
    for (int i = 0; i < n; i++)
    {
        char a = pairs(s[i]); //取出对应的字符
        if (a)                //字符为右括号时
        {
            if (top == 0 || stack[top - 1] != a) //栈中无元素或与栈顶元素不匹配
                return false;
            top--;               //有一组括号时,栈顶元素出栈
        }
        else                   //字符为左括号时
            stack[top++] = s[i]; //入栈
    }
    return top == 0; //栈中无元素,则返回True
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值