【LeetCode题集】 线性枚举的原地算法入门,这一篇就够了

目录

2057. 值相等的最小索引

26. 删除有序数组中的重复项 

 217. 存在重复元素

 2154. 将找到的值乘以 2

27. 移除元素 


这是一篇LeetCode入门级级题目解析,适合刚开始学习C语言或者刚开始刷力扣题目的同学。

题目都相对简单,相信大家都能够看得懂。如果对你有所帮助,我万分荣幸!

2057. 值相等的最小索引

题目:给你一个下标从 0 开始的整数数组 nums ,返回 nums 中满足 i mod 10 == nums[i] 的最小下标 i ;如果不存在这样的下标,返回 -1 。

x mod y 表示 x 除以 y 的 余数 。

题目传送门

解题思路:

线线扫描:若找到符合条件的下标就返回,若遍历完还没找到,就返回-1. 

int smallestEqual(int* nums, int numsSize) 
{
    for(int i=0; i<numsSize; i++)
    {
        if(nums[i] == i%10)
        {
            return i;
        }
    }
    return -1;
} 

26. 删除有序数组中的重复项 

题目:给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么?nums?的前 k 个元素应该保存最终结果。
将最终结果插入?nums 的前 k 个位置后返回 k 。
不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

题目传送门

解题思路:

法一:利用两个指针,快的用来扫描数组,慢的用来记录不重复数组的最大下标。
fast扫描数组,如果找到相邻的数组值不一样,就把fast指向的的数组值赋给low指向的位置,low值加一,fast继续扫描,直到扫描完数组所有的值为止。

 fast扫描完后,low指向的位置是不重复数组最大下标的下一个位置,可表示不重复数组的大小,故,直接返回low即可。

int removeDuplicates(int* nums, int numsSize)
{
    if(numsSize == 0)
    {
        return 0;
    }
    int low=1;
    int fast=1;
    while(fast<numsSize)
    {
        if(nums[fast]!=nums[fast-1])
        {
            nums[low]=nums[fast];
            low++;
        }
        fast++;
    }
    return low;
}

 法二:利用两个指针,快的用来扫描数组,慢的用来记录当前不重复数组的最大下标。
fast扫描数组,若遇到fast指向的数组值不等于low指向的值时,先让low加一,再把fast指向的值赋给low,直到fast扫描完数组为止。
扫描结束,low指向的是不重复数组的最大下标,不是不重复数组的大小,故要返回low+1表示数组大小。

int removeDuplicates(int* nums, int numsSize)
{
    int low = 0;
    int fast = 0;
    while(fast < numsSize)
    {
        if(nums[fast] != nums[low])
        {
            low++;
            nums[low] = nums[fast];
        }
        fast++;
    }
    return low+1;
}

 217. 存在重复元素

题目:给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false 。

题目传送门

解题思路:

法一:枚举法。两次遍历查找重复元素,时间复杂度为O(n^2),超出时间限制 

bool containsDuplicate(int* nums, int numsSize){
    if(numsSize <= 1)
    {
    	return false;
	}
    for(int i=0; i<numsSize-1; i++)
    {
        for(int j=i+1; j<numsSize; j++)
        {
            if(nums[i] == nums[j])
            {
            	return true;
			}
        }
    }
    return false;
}

 法二:排序 ,若相邻元素值相等,则说明有重复元素,时间复杂度为:O(nlogn) 

int cmp(const void* _a, const void* _b) {
    int* a = (int*)_a;
	int* b = (int*)_b;
	//return *a > *b; 
    return *a - *b;   //升序排序 
}

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

法三:哈希表

对于数组中每个元素,我们将它插入到哈希表中。如果插入一个元素时发现该元素已经存在于哈希表中,则说明存在重复的元素。

C语言哈希表参考学习

struct hashTable {    //定义哈希表
    int key;
    UT_hash_handle hh;
};

bool containsDuplicate(int* nums, int numsSize) {
    struct hashTable* set = NULL;
    for (int i = 0; i < numsSize; i++) {
        struct hashTable* tmp;
        HASH_FIND_INT(set, nums + i, tmp);
        if (tmp == NULL) {
            tmp = malloc(sizeof(struct hashTable));
            tmp->key = nums[i];
            HASH_ADD_INT(set, key, tmp);
        } else {
            return true;
        }
    }
    return false;
}

 2154. 将找到的值乘以 2

题目:给你一个整数数组 nums ,另给你一个整数 original ,这是需要在 nums 中搜索的第一个数字。
接下来,你需要按下述步骤操作:
如果在 nums 中找到 original ,将 original乘以 2 ,得到新 original(即,令 original = 2 * original)。
否则,停止这一过程。
只要能在数组中找到新 original ,就对新 original 继续 重复 这一过程。
返回 original 的 最终 值。 

题目传送门

解题思路:

方法:排序,依次找数组中是否有等于original的值,如果有,就把original*2.由于大的数字都排在后面,故不会漏值 

int cmp(const void* _a, const void* _b)
{
    int* a = (int*)_a;
    int* b = (int*)_b;
    return *a > *b;
}
int findFinalValue(int* nums, int numsSize, int original){
   /*陷阱:original*2以后,在已经遍历过的部分可能会找到新的original,由于遍历不会返回就会导致漏值 
    for(int i=0; i<numsSize; i++)
    {
        if(nums[i] == original)
        {
            original = 2*original;
        }
    }
    return original;
    */
    qsort(nums, numsSize, sizeof(int), cmp);
    for(int i=0; i<numsSize; i++)
    {
        if(original == nums[i])
        {
            original = 2*original;
        }  
    }
     return original;
}

 提供一种思路:若在数组中找到等于original的元素就从新遍历数组,一直循环的遍历数组,直到数组中没有等于original的元素。该方法时间复杂度过高,故不推荐,可以作为扩展思路。 

27. 移除元素 

题目:给你一个数组 nums和一个值 val,你需要 原地 移除所有数值等于?val?的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

题目传送门

解题思路:

法一:快慢指针 
用两个指针,快的用来扫描数组,慢的用来记录不含val值的数组的最大下标。
fast扫描数组,如果fast指向的元素值不等于val,就把fast指向的的数组值赋给low指向的位置,low值加一,fast继续扫描,直到扫描完数组所有的值为止
 fast扫描完后,low指向的位置是不重复数组最大下标的下一个位置,可表示不重复数组的大小,故,直接返回low即可。 

int removeElement(int* nums, int numsSize, int val)
{
    if(numsSize == 0)
    {
        return 0;
    }
    int low = 0;
    int fast = 0;
    while(fast != numsSize)
    {
        if(nums[fast] != val)
        {
            nums[low] = nums[fast];
            low++;
        }
        fast++;
    }
    return low;
}

法二:双指针 (次方法非本人想到的,参考了leetcode官方题解,但学会了就成了我们自己的东西)此法改变原数组元素间的相对位置 
使用双指针,两个指针初始时分别位于数组的首尾,向中间移动遍历该序列。
如果左指针left 指向的元素等于val,此时将右指针right 指向的元素复制到左指针
left的位置,然后右指针right左移一位。如果赋值过来的元素恰好也等于val,可以
 继续把右指针right 指向的元素的值赋值过来(左指针left 指向的等于val 的元素的位
 置继续被覆盖),直到左指针指向的元素的值不等于val 为止。
当左指针eft 和右指针 right 重合的时候,左右指针遍历完数组中所有的元素。
这样的方法两个指针在最坏的情况下合起来只遍历了数组一次。

与方法一不同的是,方法二避免了需要保留的元素的重复赋值操作。

int removeElement(int* nums, int numsSize, int val)
{
    int left = 0;
    int right = numsSize;
    while(left < right)
    {
        if(nums[left] == val)
        {
            nums[left] = nums[right-1];
            right--;
        }
        else
        {
            left++;
        }
    }
    return left;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值