1.数组
数组(Array)是有序的元素序列。为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式。 这些有序排列的同类数组元素的集合称为数组。
整型数组的长度:
int a[] = {1 , 3 , 5 , 7};
int length = sizeof(a) / sizeof(int);
length即为数组a的长度。
C语言中对数组的排序的函数:
qsort函数,包含在C 标准库 #include<stdlib.h>中。
qsort(需要被排序的数组,数组元素个数,每个元素大小,排序函数名)
排序函数就是由qsort函数的使用者自己定义的两个元素排大小准则。
int compare(const void* e1, const void* e2)
{
int* p1 = e1;
int* p2 = e2;
if (*p1 > *p2)
{
return 1;
}
else if (*p1 == *p2)
{
return 0;
}
else if (*p1 < *p2)
{
return -1;
}
}
int compare(const void* e1, const void* e)
排序函数的参数类型 一定是const void*
const—可以使在函数运行的过程中 原数组的值不被改变
void—是为了提升函数普适性,强制规定函数参数为void*
函数返回类型规定int
int* p1 = e1;
int* p2 = e2;
void*指针不能直接使用,所以创建两个整形指针储存原指针(被排序元素什么类型就用什么指针)
if (*p1 > *p2)
{
return 1;
}
else if (*p1 == *p2)
{
return 0;
}
else if (*p1 < *p2)
{
return -1;
}
这部分则为使用者自己定义的比较大小准则,如果该情况为大于则返回一个>0的值,如果小于返回一个<0的值,如果等于,则返回0
具体例子:
数组排序:
#include<stdio.h>
#include<stdlib.h>
int compare(const void* e1, const void* e2)
{
int* p1 = e1;
int* p2 = e2;
if (*p1 > *p2)
{
return 1;
}
else if (*p1 == *p2)
{
return 0;
}
else if (*p1 < *p2)
{
return -1;
}
}
int main()
{
int arr[10] = { 1,3,5,7,9,2,4,6,8,10 };
qsort(arr, 10, 4, compare);
for (int i = 0; i <= 9; i++)
{
printf("%d ", arr[i]);
}
}
字符数组排序:
#include<stdio.h>
#include<stdlib.h>
int compare(const void* e1, const void* e2)
{
char* p1 = e1;
char* p2 = e2;
if (*p1 > *p2)
{
return 1;
}
else if (*p1 == *p2)
{
return 0;
}
else if (*p1 < *p2)
{
return -1;
}
}
int main()
{
char arr[10] = { 'a','c','b','d','h','g','t','n' ,'w'};
qsort(arr, 9, 1, compare);
printf("%s", arr);
}
字符串排序:
#include<stdio.h>
#include<stdlib.h>
int compare(const void* e1, const void* e2)//规定按首字母顺序排序
{
char* p1 = e1;
char* p2 = e2;
if (*p1 > *p2)
{
return 1;
}
else if (*p1 == *p2)
{
return 0;
}
else if (*p1 < *p2)
{
return -1;
}
}
int main()
{
char arr1[5] = "abc";
char arr2[5] = "bcd";
char arr3[5] = "cdf";
char arr4[5] = "gnm";
char* arr[4] = { arr1,arr2,arr3,arr4 };//定义了一个指针数组来存放四个字符串数组的指针(数组名为数组第一个元素地址)
qsort(arr, 4, 4, compare);//每个元素均为指针,指针大小为4字节
printf("%s %s %s %s", arr1,arr2,arr3,arr4);
}
结构体排序:
#include<stdio.h>
#include<stdlib.h>
struct stu
{
int grade;
char name[20];
char sex[10];
};
int compare(const void* e1, const void* e2)//规定按成绩排序
{
struct stu* p1 = e1;
struct stu* p2 = e2;
if (p1->grade > p2->grade)
{
return 1;
}
else if (p1->grade==p2->grade)
{
return 0;
}
else if (p1->grade < p2->grade)
{
return -1;
}
}
int main()
{
struct stu a = { 90,"zhangsan","man" };
struct stu b = { 80,"lisi","man" };
struct stu c = { 70,"wangwu","man" };
struct stu arr[3] = { a,b,c };
qsort(arr, 3, sizeof(a), compare);
for (int i = 0; i <= 2; i++)
printf("%d %s %s\n", arr[i].grade, arr[i].name, arr[i].sex);
}
【1】两数之和
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 :
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
int main(){
int a[] = {2 , 7 , 11 , 15};
int target = 9;
int n = sizeof(a) / sizeof(int);
for(int i = 0; i < n ; i++){
for(int j = i + 1; j < n; j++){
if(target == a[i] + a[j]){
printf("[");
printf("%d", i + 1);
printf(",");
printf("%d", j + 1);
printf("]");
break;
}
}
}
}
【2】三数之和
给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。请
你返回所有和为 0
且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 :
输入: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] 。 注意,输出的顺序和三元组的顺序并不重要。
先对数组进行排序,然后一层for循环遍历最小的数,循环内用双指针寻找另外两数
找到正确结果后再去重
/**
* 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** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
int base=100; //数组的初始长度,可更改
int** a=(int**)malloc(sizeof(int*)*base);
*returnColumnSizes=(int*)malloc(sizeof(int)*base);
*returnSize=0; //初始化
int i,j,k=0,mid,right,temp;
for(i=0;i<numsSize;i++){
for(j=i+1;j<numsSize;j++){
if(nums[j]<nums[i]){
temp=nums[i];
nums[i]=nums[j];
nums[j]=temp;
}
else continue;
}
} //选择排序
for(i=0;i<numsSize;i++){
if(i>0&&nums[i]==nums[i-1]){continue;} //对i向左去重,(向右会忽略-1,-1,2)
mid=i+1;right=numsSize-1; //定义双指针
while(mid<right){
if(nums[i]+nums[mid]+nums[right]==0){
a[*returnSize]=(int*)malloc(sizeof(int)*3); //每一个数组大小都为3
(*returnColumnSizes)[*returnSize]=3; //给申请的空间赋值
a[*returnSize][0]=nums[i];
a[*returnSize][1]=nums[mid];
a[*returnSize][2]=nums[right];
(*returnSize)++; //行自增
int num1=nums[mid],num2=nums[right]; //对mid,right去重
while(nums[mid]==num1&&mid<right){mid++;}
while(nums[right]==num2&&mid<right){right--;}
if(*returnSize==base){
base*=2;
a=(int**)realloc(a,sizeof(int*)*base);
*returnColumnSizes=(int*)realloc(*returnColumnSizes,sizeof(int)*base);
}//如果二维数组的大小达到初始设定的行数,则进行空间扩容
}//找到目标数组
else if(nums[i]+nums[mid]+nums[right]<0)
mid++;
else right--;
}
}//i遍历最小的数,mid从i+1开始,寻找中间的数,right为右指针
return a;
}
【3】删除有序数组中的重复项
给你一个 升序排列 的数组 nums
,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k
个元素,那么 nums
的前 k
个元素应该保存最终结果。
将最终结果插入 nums
的前 k
个位置后返回 k
。
不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
判题标准:
系统会用下面的代码来测试你的题解:
int[] nums = [...]; // 输入数组 int[] expectedNums = [...]; // 长度正确的期望答案 int k = removeDuplicates(nums); // 调用 assert k == expectedNums.length; for (int i = 0; i < k; i++) { assert nums[i] == expectedNums[i]; }
如果所有断言都通过,那么您的题解将被 通过。
示例 :
输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。
前后比较,遇到不相同的项,则在数组对应的位置写入即可
int removeDuplicates(int* nums, int numsSize){
int k = 0,i;
for(i = 1; i < numsSize; i++){
if(nums[i - 1] != nums[i])
nums[++k] = nums[i]; //++k而不是k++,因为下标为0的元素一定在新数组中
}
return k + 1; //k+1才是返回的长度
}
【4】移除元素
给你一个数组 nums
和一个值 val
,你需要 原地 移除所有数值等于 val
的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1)
额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
说明:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝 int len = removeElement(nums, val); // 在函数里修改输入数组对于调用者是可见的。 // 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。 for (int i = 0; i < len; i++) { print(nums[i]); }
示例 :
输入:nums = [3,2,2,3], val = 3 输出:2, nums = [2,2] 解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
int removeElement(int* nums, int numsSize, int val){
int k = 0,i;
for(int i = 0; i < numsSize; i++ ){
if(val != nums[i]){
nums[k++] = nums[i];
}
}
return k;
}
【5】搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n)
的算法。
示例 :
输入: nums = [1,3,5,6], target = 5 输出: 2
int searchInsert(int* nums, int numsSize, int target){
int left=0;
int right=numsSize-1;//若左右闭区间,则需要将长度转化为数组形式,因正常长度0是没有意义的,但是0在数组中充当数字的索引。
while(left<=right){//因为是左右均是闭区间,因此可以出现数字相等
int middle=left+((right-left)/2);//防止溢出,其效果等同(left+right)/2
if(nums[middle]<target){
left=middle+1;
}else if (nums[middle]>target){
right=middle-1;
}
else{
return middle;
}
}
return right+1;//此时需要改变的数字应在right的右边,故加一
}
//复杂空间为O(long_n)一般是要用二分法处理。
【6】合并区间
以数组 intervals
表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi]
。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例 :
输入:intervals = [[1,3],[2,6],[8,10],[15,18]] 输出:[[1,6],[8,10],[15,18]] 解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
c++来做简单些
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
int n=intervals.size();
vector<vector<int>>nums;
sort(intervals.begin(),intervals.end());
for(int i=0;i<n;i++){
int L=intervals[i][0],R=intervals[i][1];
if(nums.size()==0||nums.back()[1]<L){
nums.push_back({L,R});
}else{
nums.back()[1]=max(nums.back()[1],R);
}
}
return nums;
}
};
【7】合并两个有序数组
给你两个按 非递减顺序 排列的整数数组 nums1
和 nums2
,另有两个整数 m
和 n
,分别表示 nums1
和 nums2
中的元素数目。
请你 合并 nums2
到 nums1
中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1
中。为了应对这种情况,nums1
的初始长度为 m + n
,其中前 m
个元素表示应合并的元素,后 n
个元素为 0
,应忽略。nums2
的长度为 n
。
示例 :
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 输出:[1,2,2,3,5,6] 解释:需要合并 [1,2,3] 和 [2,5,6] 。 合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
#include <stdio.h>
#include <stdlib.h>
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
// 开辟一个新数组,用来存放合并后的结果
int* ret = (int*)malloc(sizeof(int) * (m + n));
// 初始化三个指针,用来遍历三个数组
int cur1 = 0, cur2 = 0, dest = 0;
// 当其中一个遍历到数组的结尾,我们就结束循环
while (cur1 < m && cur2 < n)
{
// 当第一个数组的元素比较小的时候,我们就加入合并后的数组
if (nums1[cur1] <= nums2[cur2])
ret[dest++] = nums1[cur1++];
// 否则就将第二个元素加入到目标数组
else
ret[dest++] = nums2[cur2++];
}
// 下面两个循环只会执行一个,因为只会有一个数组还有剩余元素
// 当第一个数组的元素有剩余的话,就会执行第一个循环
while (cur1 < m)
ret[dest++] = nums1[cur1++]; // 将数组的内容拷贝到合并后的数组中
// 当第二个数组的元素有剩余的话,就会执行第二个循环
while (cur2 < n)
ret[dest++] = nums2[cur2++];
// 将合并后的数组,放回第一个数组中去
for (int i = 0; i < m + n; i++)
{
nums1[i] = ret[i];
}
// 释放辅助数组
free(ret);
}
【8】杨辉三角
给定一个非负整数 numRows
,生成「杨辉三角」的前 numRows
行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。
示例 1:
输入: numRows = 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]
/**
* 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** generate(int numRows, int* returnSize, int** returnColumnSizes){
int** ret = malloc(sizeof(int*)*numRows); //申请返回的指针空间
*returnSize = numRows; //返回行数
*returnColumnSizes = malloc(sizeof(int*)*numRows); //为每一列分配空间
for(int i=0;i<numRows;i++)
{
ret[i] = malloc(sizeof(int)*(i+1));
//分配每一行的个数
(*returnColumnSizes)[i] = i + 1;
//为第一个以及最后一个赋值
ret[i][0] = 1;
ret[i][i] = 1;
for(int j=1;j<i;j++)
{
ret[i][j] = ret[i-1][j-1] + ret[i-1][j];
}
}
return ret;
}
【9】杨辉三角||
给定一个非负索引 rowIndex
,返回「杨辉三角」的第 rowIndex
行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。
示例 1:
输入: rowIndex = 3 输出: [1,3,3,1]
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* getRow(int rowIndex, int* returnSize){ //returnSize 代表传出数组的长度
*returnSize = rowIndex+1; //为returnSize赋值
//由于返回是数组,故需要创建一个数组
int* ret[rowIndex + 1];
//循环遍历
for(int i=0;i<=rowIndex;i++)
{
//为每一行申请空间
ret[i] = malloc(sizeof(int)*(i+1));
//每一行中首元素和尾元素为1
ret[i][0] = ret[i][i] = 1;
//循环为每一行其余元素赋值
for(int j=1;j<i;j++)
{
ret[i][j] = ret[i-1][j] + ret[i-1][j-1];
}
}
return ret[rowIndex]; //返回对应rowIndex行
}