Leetcode刷题---线性枚举之统计法入门

本文是(第18讲) 线性枚举(二) - 统计法入门所涉及课后习题的解答,发帖来记录自己关于这些题的理解和做题过程中思路,如果有错误,欢迎批评指正。

在开始之前,首先 恭喜EDG!鏖战五局,为LPL捧回总冠军奖杯。

好了,开始今天的刷题。

1.统计位数为偶数的数字

题目:给你一个整数数组 nums,请你返回其中位数为 偶数 的数字的个数。

主要思路:可以利用字符串取数字位数或者数学方法取数字位数。

代码:

class Solution {
public:
    //利用字符串取数字位数
   // bool bitIsEven(int n){
    //     string s=to_string(n);
    //     return s.size()%2==0? true : false;
    // }
	//利用数学方法取数字位数
    bool bitIsEven(int n){
        int bit=0;
        while(n){
            n/=10;
            bit++;
        }
        return bit%2==0? true:false;
    }
    int findNumbers(vector<int>& nums) {
        int ans=0;
        for(auto num:nums){
            if(bitIsEven(num)){
                ans++;
            }
        }
        return ans;
    }
};

2.有序数组中的单一元素

题目:给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数。

主要思路:利用异或运算,两个相同的数异或为0,将数组中所有数异或,即可得到唯一的那个数。

代码:

class Solution {
public:
    int singleNonDuplicate(vector<int>& nums) {
        int ans=0;
        for(auto num:nums){
            ans^=num;
        }
        return ans;
    }
};

3.调整数组顺序使奇数位于偶数前面

题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数在数组的前半部分,所有偶数在数组的后半部分。

主要思路:使用双指针,从头尾向中间遍历,当前面的数为奇数时,左指针右移;当后面的数为偶数时,右指针左移;当前偶后奇时,交换两数。最后将结果数组返回。

指针:

class Solution {
public:
    vector<int> exchange(vector<int>& nums) {
        int i=0,j=nums.size()-1;
        while(i<j){
            if(nums[i]%2==0 && nums[j]%2==1){
                nums[i]=nums[i]+nums[j];
                nums[j]=nums[i]-nums[j];
                nums[i]=nums[i]-nums[j];
                i++;
                j--;
            }
            else if(nums[i]%2==1){
                i++;
            }else if(nums[j]%2==0){
                j--;
            }
        }
        return nums;
    }
};

4.找到数组的中间位置 & 寻找数组的中心下标

题目:给你一个下标从 0 开始的整数数组 nums ,请你找到 最左边 的中间位置 middleIndex,中间位置即为数组中该位置左边和与右边和相等,将左边界的左边和和右边界的右边和视为0。

主要思路:先求出数组总和sum,从头开始遍历每个数,并计算当前位置i左边部分的和leftSum,当leftSum=sum-nums[i]-leftSum时(即2*leftSum+nums[i]=sum时),该位置即为要求的中间位置。

代码:

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

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

题目:给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。

主要思路:使用快慢指针,快指针用于遍历每个数,慢指针用于将不重复的数前移。

代码:

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int i=1,j=1;
        if(nums.size()==0){
            return 0;
        }
        while(j<nums.size()){
            if(nums[j]!=nums[j-1]){
                nums[i]=nums[j];
                i++;
            }
            j++;
        }
        return i;
    }
}; 

6.可被5整除的二进制前缀

题目:给定由若干 0 和 1 组成的数组 A。我们定义 N_i:从 A[0] 到 A[i] 的第 i 个子数组被解释为一个二进制数(从最高有效位到最低有效位)。返回布尔值列表 answer,只有当 N_i 可以被 5 整除时,答案 answer[i] 为 true,否则为 false。

主要思路:遍历数组,使用temp变量,通过累加公式temp=temp*2+nums[i]来表示当前遍历到的子数组所代表的二进制值,例如,对nums=[1,1,1] temp=0,有

i=0时, temp=0*2+1=1

i=1时,temp=1*2+1=3

i=2时,temp=3*2+1=7

然后不断循环,不断判断是否能被5整除,并将结果存入ans数组中。

需要注意的是,由于代码中采用了累加的方法,所以可能溢出,溢出产生于公式temp=temp2+nums[i]中temp2部分,所以让其对5取余,可以防止溢出。前面有学习过,(ab)%c=(a%c)(b%c)%c,所以temp=temp*2+nums[i]=((temp%5)*2)%5+nums[i]。

为什么这样可以呢?拿14举例,14+1=(72)+1=15可以被5整除,(7%52)%5+1=5可以被5整除,即若temp2+nums[i]可以被5整除,那么(temp2)%5+nums[i]也一定能被5整除。

代码:

class Solution {
public:
    vector<bool> prefixesDivBy5(vector<int>& nums) {
        int temp=0;
        vector<bool> ans;
        for(int i=0;i<nums.size();i++){
            temp=((temp%5)*2)%5+nums[i];
            if(temp%5==0){
                ans.push_back(true);
            }
            else{
                ans.push_back(false);
            }
        }
        return ans;
    } 
};

7.可被k整除的最小整数

题目:给定正整数k,你需要找出可以被 k整除的、仅包含数字1 的最小正整数 N。返回 N的长度。如果不存在这样的 N,就返回 -1。

代码:

class Solution {
public:
    int smallestRepunitDivByK(int k) {
        if(k%2==0 || k%5==0){
            return -1;
        }
        int ans=1,temp=1;
        while(temp%k){
            temp%=k; //防止溢出
            temp=temp*10+1;
            ans++;
        }
        return ans;
    }
}; //枚举法

8.哪种连续子串更长

题目:给你一个二进制字符串s。如果字符串中由1组成的 最长 连续子字符串 严格长于 由 0组成的 最长 连续子字符串,返回 true ;否则,返回 false 。

主要思路:遍历数组,分别统计连续的1和0的长度,最后比较即可。

代码:

class Solution {
public:
    bool checkZeroOnes(string s) {
        int m=0,n=0,one=0,zero=0;
        for(int i=0;i<s.size();i++){
            if(s[i]=='1'){
                m++;
                if(i!=s.size()-1 && s[i]!=s[i+1]){
                    one=max(one,m);
                    m=0;
                }
            }else{
                n++;
                if(i!=s.size()-1 && s[i]!=s[i+1]){
                    zero=max(zero,n);
                    n=0;
                }
            }
        }
        one=max(one,m);
        zero=max(zero,n);
        return one>zero;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值