Leetcode 初级算法 数组 C语言解答

Leetcode 初级算法 数组

      • 26. 从排序数组中删除重复项
      • 122. 买卖股票的最佳时机 II
      • 189. 旋转数组
      • 217. 存在重复元素
      • 136. 只出现一次的数字
      • 350. 两个数组的交集 II
      • 66. 加一
      • 283. 移动零
      • 1. 两数之和
      • 36. 有效的数独
      • 48. 旋转图像

26. 从排序数组中删除重复项

26. 从排序数组中删除重复项

  • 算法思想:
    本算法类似于插入排序法,从元素0到元素number为已处理过的排序数组,从元素cur到数组末为未处理的数组,把每一个不重复的元素赋值到已处理过的排序数组,最后返回总长度为number+1。
  • 算法时间复杂度O(n)
int removeDuplicates(int* nums, int numsSize) {
    if(numsSize == 0){
        return 0;
    }
	int number = 0;
	for(int cur = 0; cur < numsSize; cur++){
    	if(nums[cur] != nums[number]){
       		number++;
       		nums[number] = nums[cur];
    	}
	}
	return ++number;
}

122. 买卖股票的最佳时机 II

122. 买卖股票的最佳时机 II

  • 算法思想:
    本算法将股票价格数组的处理变为每天与之前一天价格的差值,股价升高时判断有利润可交易,遍历一次数组。
  • 算法时间复杂度O(n)
int maxProfit(int* prices, int pricesSize) {
    int profit = 0;
    for(int i=0; i<pricesSize-1; i++){
        int temp = prices[i+1]-prices[i];
        if(temp>0)
            profit += temp;
    }
    return profit;
}

189. 旋转数组

189. 旋转数组

  • 算法思想:
    本算法将旋转分为三步的倒换
  • 算法时间复杂度O(n)
void rotate(int* nums, int numsSize, int k) {
    k = k%numsSize;
	if (k == 0)
		return;
	reverse(&nums[0], &nums[numsSize - k - 1]);
	reverse(&nums[numsSize - k], &nums[numsSize - 1]);
	reverse(&nums[0], &nums[numsSize - 1]);
}

void reverse(int*left, int*right){
	while (left < right){
		int temp = *left;
		*left = *right;
		*right = temp;
		left++;
		right--;
    }
}

217. 存在重复元素

217. 存在重复元素

  • 算法思想:
    本算法将数组进行排序,遍历一遍检查相邻元素是否相同
  • 算法时间复杂度O(nlogn)
int cmp(const void *a, const void *b){
	return *(int*)a - *(int *)b;
}

bool containsDuplicate(int* nums, int numsSize){
    if((NULL == nums) || (numsSize < 2))
		return false;
		
    qsort(nums, numsSize, sizeof(nums[0]), cmp);
    for (int i = 0; i < numsSize-1; i++){
		if (nums[i] == nums[i+1])
			return true;
	}
	return false;
}

136. 只出现一次的数字

136. 只出现一次的数字

  • 算法一思想:
    本算法将数组进行排序,遍历一遍检查nums[2k]是否与下一个元素相等,单次出现的元素必定出现在不一致的nums[2k]上。
  • 算法时间复杂度O(nlogn)
  • 算法二思想:
    本算法来自Leetcode大佬们,通过将数组中所有元素与0进行异或,出现过两次的元素异或后仍未0,单次出现的元素异或后为原值;遍历一遍后可以得出单次出现的元素。
  • 算法时间复杂度O(n)
//算法一
int cmp(const void *a, const void *b){
	return *(int*)a - *(int *)b;
}

int singleNumber(int* nums, int numsSize) {
    int i;
    qsort(nums, numsSize, sizeof(nums[0]), cmp);
    for (i = 0; i < numsSize-1; i+=2){
		if (nums[i] != nums[i+1])
			return nums[i];
	}
    return nums[i];
}
//算法二
int singleNumber(int* nums, int numsSize) {
    int result = 0;
    for(int i=0; i<numsSize; i++)
        result ^= nums[i];
    return result;
}

350. 两个数组的交集 II

350. 两个数组的交集 II

  • 算法思想:
    本算法将两个数组进行排序,一起遍历两个数组,当遇到相同的元素时复制到新的数组中。
    Tips:注意这里的分配空间的函数
  • 算法时间复杂度O(nlogn)
int cmp(const void *a,const void *b)
{
return *(int *)a > *(int *)b ? 1 : -1;
}
int* intersect(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize) {
    if(nums1Size==0 || nums2Size==0)
    	return NULL;
    int i=0,j=0;
    int *newnums=(int*)malloc(sizeof(int)*nums1Size);
    qsort(nums1, nums1Size, sizeof(nums1[0]), cmp);
    qsort(nums2, nums2Size, sizeof(nums2[0]), cmp);
    while(i<nums1Size&&j<nums2Size){
        if(nums1[i]==nums2[j]){
		    newnums[(*returnSize)++]=nums1[i];
            i++;
	        j++;
        }
        else if(nums1[i]<nums2[j])
            i++;
        else
            j++;
    }
    if(*returnSize<nums1Size)
        newnums=(int*)realloc(newnums,sizeof(int)*(*returnSize));
    return newnums;
}

66. 加一

66. 加一

  • 算法思想:
    本算法将两个数组进行排序,一起遍历两个数组,当遇到相同的元素时复制到新的数组中。
    Tips:注意这里的逻辑,当数字不全为9时,可以修改首位非9值,返回原地址,当数字为全9时,重新分配空间,位数加1。
  • 算法时间复杂度O(n)
int* plusOne(int* digits, int digitsSize, int* returnSize) {
    int i = digitsSize - 1;
    for(i;i >= 0;i--){
        if(digits[i] < 9){
            digits[i]++;
            *returnSize = digitsSize;
            return digits;
        }
        digits[i] = 0; 
    }
    int* new = (int*) malloc ((digitsSize + 1) * sizeof (int));
    new[0] = 1;
    for(i = 1;i < (digitsSize + 1);i++)
        new[i] = 0;
    *returnSize = digitsSize + 1;
    return new;
}

283. 移动零

283. 移动零

  • 算法思想:
    本算法是采用双指针,一个指针指向所有原数组的元素,另一个指针指向所有非零元素存放的位置。
  • 算法时间复杂度O(n)
void moveZeroes(int* nums, int numsSize) {
    int i = 0,j = 0;
    for(i; i<numsSize;i++)
        if (nums[i] != 0)
            nums[j++] = nums[i];
    for(j; j<numsSize; j++)
        nums[j] = 0;
}

1. 两数之和

1. 两数之和
C语言解法转载自hang-7788的文章LeetCode 1.两数之和 Two Sum (C语言)

  • 算法思想:
    1.构造结构体,将数组的值与初始位置关联起来,并对结构体数组进行从小到大的排序。
    2.使用下标begin和end,begin指向于开始的位置,end指向结束的位置,判断nums[begin] + nums[end]与target的关系。
    • 如果相等,则直接返回索引;
    • 如果比target大,则说明需要减小两数之和,即end–,来减小后者数字;
    • 如果比target大,则说明需要增大两数之和,即begin++来增大前者数字。
  • 3.通过这种方式逐渐逼近target,时间复杂度是O(nlogn)。
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
struct node {
    int val;
    int index;
};
int comp(const void* a, const void* b) {
    return (((struct node*)a)->val > ((struct node*)b)->val ? 1 : -1);
}
int* twoSum(int* nums, int numsSize, int target) {
    int i = 0;
    int n = numsSize;
    int begin = 0, end = n - 1;
    int* result = NULL;
    struct node* nodes = (struct node*)malloc(n * sizeof(struct node));
    // init nodes
    for(i = 0; i < n; i++) {
        nodes[i].val = nums[i];
        nodes[i].index = i;
    }
    qsort(nodes, n, sizeof(struct node), comp);
    while(begin < end) {
        if(nodes[begin].val + nodes[end].val == target) {
            result = (int*)malloc(sizeof(int) * 2);
            result[0] = nodes[begin].index;
            result[1] = nodes[end].index;
            free(nodes);
            return result;
        }
        else if(nodes[begin].val + nodes[end].val > target)
            end--;
        else
            begin++;            
    }
    free(nodes);
    return result;
}

36. 有效的数独

36. 有效的数独

  • 算法思想:
    维护三个分别代表行、列、块的三个数组,对于数独内每个单元值都在行、列、块中进行校验,遍历所有单元,如果全部通过即为有效
  • 时间复杂度是O(n)。
bool isValidPart(char **board, int i, int j, int *a)
{
    char c = board[i][j];
    if(c != '.')
    {
        int index = c - '1';
        if(a[index]==1)return false;
        else a[index]=1;
    }
    return true;
}


bool isValidSudoku(char** board, int boardRowSize, int boardColSize) {
    int a[9]={0};  //标记一行
    int b[9]={0};  //标记一列
    int c[9][9]={0}; //c[i]标记一个9宫格
    for(int i =0;i<9;i++)
    {
        memset(a,0,sizeof(int)*9);
        memset(b,0,sizeof(int)*9);
        for(int j=0;j<9;j++)
        {
            if(isValidPart(board, i, j, a)==false)return false;
            if(isValidPart(board, j, i, b)==false)return false;
            if(isValidPart(board, i, j, c[(i/3)*3 + j/3])==false)return false;
        }
    }
    return true;
}

48. 旋转图像

48. 旋转图像

  • 算法一思想:
    将图像先转置,再对称翻转。
  • 算法时间复杂度O(n)
  • 算法二思想:
    本算法来自Leetcode大佬们,详细的过程见另一篇文章Leetcode 48. 旋转图像 C语言解答
  • 算法时间复杂度O(n)
void swap(int* a, int* b){
    *a = *a ^ *b;
    *b = *a ^ *b;
    *a = *a ^ *b;
}

void rotate(int** matrix, int matrixRowSize, int *matrixColSizes) {
    int i = 0, j = 0;
    for(i = 0; i < matrixRowSize; i++) {
        for(j = 0; j < i; j++) {
            swap(&matrix[i][j], &matrix[j][i]);
        }
    }
    for(i = 0; i < matrixRowSize; i++) {
        for(j = 0; j < matrixRowSize / 2; j++) {
            swap(&matrix[i][j], &matrix[i][matrixRowSize - 1 - j]);
        }
    }
}
void rotate(int** matrix, int matrixRowSize, int *matrixColSizes) {
    int temp, i, j;
    for(int internal = matrixRowSize; internal >= 2; internal -= 2){
        j = (matrixRowSize - internal) / 2;
        for(i = j; i < (matrixRowSize + internal) / 2 - 1; i++){
            temp = matrix[i][j];
            matrix[i][j] = matrix[matrixRowSize - j - 1][i];
            matrix[matrixRowSize - j - 1][i] = matrix[matrixRowSize - i -1][matrixRowSize - j - 1];
            matrix[matrixRowSize - i -1][matrixRowSize - j - 1] = matrix[j][matrixRowSize - i -1];
            matrix[j][matrixRowSize - i -1] = temp;
        }
    }
}

你可能感兴趣的:(C语言)