LeetCode题库-11~20-C语言
11 盛最多水的容器
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明: 你不能倾斜容器。
- 示例1:
- 输入: [1,8,6,2,5,4,8,3,7]
- 输出: 49
- 解释: 图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
- 示例2:
- 输入: height = [1,1]
- 输出: 1
- 提示:
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 整数转罗马数字
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 | 数值 |
---|---|
I | 1 |
V | 5 |
X | 10 |
L | 50 |
C | 100 |
D | 500 |
M | 1000 |
例如, 罗马数字 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:
- 输入: num = 3
- 输出: “III”
- 示例2:
- 输入: num = 4
- 输出: “IV”
- 示例3:
- 输入: num = 9
- 输出: “IX”
- 示例4:
- 输入: num = 58
- 输出: “LVIII”
- 解释: L = 50, V = 5, III = 3.
- 示例5:
- 输入: num = 1994
- 输出: “MCMXCIV”
- 解释: M = 1000, CM = 900, XC = 90, IV = 4.
- 提示:
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 罗马数字转整数
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 | 数值 |
---|---|
I | 1 |
V | 5 |
X | 10 |
L | 50 |
C | 100 |
D | 500 |
M | 1000 |
例如, 罗马数字 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:
- 输入: s = “III”
- 输出: 3
- 示例2:
- 输入: s = “IV”
- 输出: 4
- 示例3:
- 输入: s = “IX”
- 输出: 9
- 示例4:
- 输入: s = “LVIII”
- 输出: 58
- 解释: L = 50, V = 5, III = 3.
- 示例5:
- 输入: s = “MCMXCIX”
- 输出: 1994
- 解释: M = 1000, CM = 900, XC = 90, IV = 4.
- 提示:
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:
- 输入: strs = [“flower”,“flow”,“flight”]
- 输出: “fl”
- 示例2:
- 输入: strs = [“dog”,“racecar”,“car”]
- 输出: “”
- 解释: 输入不存在公共前缀。
- 提示:
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 != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。
请你返回所有和为 0 且不重复的三元组。
注意: 答案中不可以包含重复的三元组。
- 示例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:
- 输入: nums = [0,1,1]
- 输出: [ ]
- 解释: 唯一可能的三元组和不为 0 。
- 示例3:
- 输入: nums = [0,0,0]
- 输出: [[0,0,0]]
- 解释: 唯一可能的三元组和为 0 。
- 提示:
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:
- 输入: nums = [-1,2,1,-4], target = 1
- 输出: 2
- 解释: 与 target 最接近的和是 2 (-1 + 2 + 1 = 2)
- 示例2:
- 输入: nums = [0,0,0], target = 1
- 输出: 0
- 提示:
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:
- 输入: digits = “23”
- 输出: [“ad”,“ae”,“af”,“bd”,“be”,“bf”,“cd”,“ce”,“cf”]
- 示例2:
- 输入: digits = “”
- 输出: []
- 示例3:
- 输入: digits = “2”
- 输出: [“a”,“b”,“c”]
- 提示:
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:
- 输入: nums = [1,0,-1,0,-2,2], target = 0
- 输出: [[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
- 示例2:
- 输入: nums = [2,2,2,2,2], target = 8
- 输出: [[2,2,2,2]]
- 提示:
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:
- 输入: head = [1,2,3,4,5], n = 2
- 输出: [1,2,3,5]
- 示例2:
- 输入: head = [1], n = 1
- 输出: []
- 示例3:
- 输入: head = [1,2], n = 1
- 输出: [1]
- 提示:
链表中结点的数目为 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:
- 输入: s = “()”
- 输出: true
- 示例2:
- 输入: s = “()[]{}”
- 输出: true
- 示例3:
- 输入: s = “(]”
- 输出: false
- 提示:
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
}