线性枚举:统计数组中的特征数《算法零基础100讲》

模板描述
概念:对数组中具有某特性元素进行统计(如统计位数为偶数的数字,统计不含7或不能被7整除的数字…)
通法:线性枚举数组各元素,依次进行判断统计
典题
实现一个函数,给定一个数组,返回其中十进制为偶数的数的个数
方法:

//判断方法1️⃣
int isEvenBit(int num) {
              // (1)将num逐次除以十
    int bit = 0;                     //直到num为零,统计除以10的次数(bit)
    while(num) {
                          //若num为偶数,则其经过偶数次除以10后变为零
        num /= 10;         //由此我们可以通过bit是否为偶来间接判断num的奇偶
        ++bit;
    }
    return (bit % 2 == 0);
}
//------------------------------------------------------
//判断方法2️⃣
int isEvenBit(int num) {
               // (1)运用C++的to_string函数
   string jd=to_string(num);         //及string类的成员函数
   int k=jd.size();                 //通过num转化字符串的长度判断
    return k%2==0;          
}
//----------------------------------------------------------
//判断方法3️⃣
int isEvenBit(int num){
     
return (int)(log10(num)+1)%2==0;//简单的数学方法
}
//-----------------------------
int findNumbers(int* nums, int numsSize){
     
    int i, cnt = 0;
    for(i = 0; i < numsSize; ++i) {
            // (2)有了判断方法
        if(isEvenBit(nums[i]))           //我们只需遍历数组
            ++cnt;                       //逐次判断统计
    }
    return cnt;
}

上例题!开始实践!
例题1️⃣:
统计位数为偶数的数字
线性枚举:统计数组中的特征数《算法零基础100讲》_第1张图片
线性枚举:统计数组中的特征数《算法零基础100讲》_第2张图片
分析:典型的模板

class Solution {
       //一般不过的枚举统计
public:
    int findNumbers(vector<int>& nums) {
     
    int cnt=0;
    for(int i:nums){
     
        if(to_string(i).size()%2==0)cnt++;
    }
    return cnt;
    }
};

例题2️⃣:
有序数列中的单一元素
线性枚举:统计数组中的特征数《算法零基础100讲》_第3张图片
分析:思路一:数组元素较小,取一计数数组进行计数,线性枚举两遍
一次计数,一次找出计数为一的元素
思路二:根据数组的特性,取下标为偶数的元素,判断其是否与后一个元素相同

for(int i=0;i<nums.size();i+=2){
     
  if(nums[i]!=nums[i+1])return nums[i];
  }
  return nums.back();

思路三:虽然该数组未经过排序,不满足二分查找的标准模板,但,要搜索的元素只出现一次,而其他元素都出现两次,所以具备这么明显的标志,仔细思考,该题也能使用二分搜索。

class Solution {
       //二分查找模板是从有序数组搜索指定元素
public:             //这里同样适用
    int singleNonDuplicate(vector<int>& nums) {
     
        int left = 0;
        int right = nums.size() - 1;
        while (left <right) {
     
            int mid = left + (right- left) / 2;
            if (nums[mid + 1] == nums[mid]) {
     
                if ((right- mid) % 2 == 0)   left = mid + 2;                 
                 else  right= mid - 1;              
            } 
            else if (nums[mid - 1] == nums[mid]) {
     
                if ((right- mid) % 2 == 0)  right= mid - 2;
                else  left = mid + 1;             
            } 
            else return nums[mid];        
        }
        return nums[left];
    }
};

线性枚举:统计数组中的特征数《算法零基础100讲》_第4张图片
这是我所能想出的最快解法,而官方题解给出了“仅对偶数索引进行二分搜索”,我还是差了一点啊‍,当然这里不做扩展。

例题3️⃣:
剑指offer 调整数组顺序,是奇数位于偶数前面

class Solution {
     
public:          //创建临时数组,遍历nums,先放奇数后放偶数
    vector<int> exchange(vector<int>& nums) {
     
    vector<int>jie;
    for(int i=0;i<nums.size();i++){
     
        if(nums[i]&1)jie.push_back(nums[i]);
    }
     for(int i=0;i<nums.size();i++){
     
        if(!(nums[i]&1))jie.push_back(nums[i]);
    }
    return jie;
    }
};

当然双指针,咳咳,这里还是先不拓展了‍
线性枚举:统计数组中的特征数《算法零基础100讲》_第5张图片
例题4️⃣:
找到数组的中间位置
例题5️⃣:
寻找数组的中心下标
(两题相同)
线性枚举:统计数组中的特征数《算法零基础100讲》_第6张图片
线性枚举:统计数组中的特征数《算法零基础100讲》_第7张图片
分析:若存在中间元素k,则k左边的元素和sum1等于k右边的元素和sum2,
即sum1+sum2+k=2*sum1+k=sum(数组元素总和)
由此:

class Solution {
     
public:
    int pivotIndex(vector<int> &nums) {
     
        int sum = accumulate(nums.begin(), nums.end(), 0);
        int sum1 = 0;
        for (int i = 0; i < nums.size(); ++i) {
     
            if (2 * sum1 + nums[i] == sum)   return i;    
            sum1 += nums[i];
        }
        return -1;
    }
};

补充:
C++STL,accumulate用法:
函数原型:int accumulate(首地址,尾地址,int val).可以返回从首地址到尾地址的元素总和+val.
例题6️⃣:
删除有序序列中的重复项
线性枚举:统计数组中的特征数《算法零基础100讲》_第8张图片
线性枚举:统计数组中的特征数《算法零基础100讲》_第9张图片

class Solution {
     
public:
    int removeDuplicates(vector<int>& nums) {
     
        int n=nums.size();
        if(n==0) return 0; //如果nums元素为零,直接返回0
        int tmp=nums[0];   
        for( vector<int>::iterator it=nums.begin()+1;it!=nums.end();){
     
            if(*it==tmp) {
     tmp=*it;nums.erase(i);} //用迭代器遍历数组
            else {
     tmp = *it;it++;}          //如果数组元素*it等于tmp,说明存在重复元素,erase删除
        }                          //否则,更新tmp为*it
        return nums.size();   //返回数组长度
    }
};

例题7️⃣:
可被5整除的二进制前缀
线性枚举:统计数组中的特征数《算法零基础100讲》_第10张图片
线性枚举:统计数组中的特征数《算法零基础100讲》_第11张图片

分析:观察发现,这里的01数组长度很大,最坏有2^30000,我们不能直接求出每个N_i,否则计算量过大,会溢出,就算用快速幂,也一样会超时,怎嘛办——
(a+b)%c=(a%c+b%c)%c;
(ab)%c=(a%c)(b%c)%c;
从A[0]开始,N_0=A[0]2^0=A[0]1,设每次结果N_i%5的结果为k_i
N_1=(N_0)*2+A[1]*1;
简化得:
N_1=(N_0%5)*2+A[1]*1=k_0
*2+A[1]
由此数学归纳可得:
N_i=(N_(i-1)%5)*2+A[1]*1=k_(i-1)*2+A[i]
这意味着,我们只需计算每一步的k_(i-1)即可推之k_i
而k_i<5,这样我们便可以轻易地将题目解开

class Solution {
     
public:
    vector<bool> prefixesDivBy5(vector<int>& nums) {
     
        vector<bool>res;
        int k = 0;
        for (int i = 0; i <nums.size(); i++) {
     
            k = (nums[i]+(k << 1) ) % 5;//用上一步的k_(i-1)
            res.push_back(k== 0);      //推出这一步的k_i,储存结果
        }
        return res;
    }
};

例题8️⃣:
可被k整除的最小整数
线性枚举:统计数组中的特征数《算法零基础100讲》_第12张图片
分析:和上一题相似的思路
注意:找不到111…是2或5的倍数

class Solution {
     
public:
    int smallestRepunitDivByK(int k) {
     
    if(k%2==0||k%5==0)return -1;//注意,没有这一步会出现死循环
    int tmp=0;
    for(int i=1;;i++){
     
    tmp=(tmp*10+1)%k;  //和上一题相似k%5==
    if(tmp==0)return i;
    }
    }
};

例题9️⃣:
那种连续子字符串更长
线性枚举:统计数组中的特征数《算法零基础100讲》_第13张图片
线性枚举:统计数组中的特征数《算法零基础100讲》_第14张图片
分析:这一题较简单,遍历一遍即可

class Solution {
     
public:
    bool checkZeroOnes(string s) {
     
    int t1=0,t0=0;
    int max1=0,max0=0;
    for(int i=0;i<s.size();i++){
     
        if(s[i]-'0'==1){
     
            t1++;
            max0=max(max0,t0); //开始记录
            max1=max(max1,t1);//持续更新最大连续长度![在这里插入图片描述](https://img-blog.csdnimg.cn/ee99c99e94b946afab1f87b7c32a5899.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAMF91TDzop6PpopjogIUx,size_18,color_FFFFFF,t_70,g_se,x_16#pic_center)

            t0=0;
            }
        else{
     
            t0++;
            max0=max(max0,t0);
            max1=max(max1,t1);
            t1=0;
        }
    }
    return max1>max0;
    }
};

你可能感兴趣的:(l算法学习笔记(力扣),算法,leetcode,职场和发展)