1.线性遍历:线性遍历就是通过循环,将一个数组的数据按线性的方式依次遍历
例如:将一个数组内的数据全部打印一遍
void line(int* nums, int* numsSize){
for(int i = 0; i < numsSize; i++){
printf("%d ", nums[i]);
}
printf("\n");
}
2.计算十进制数据的位数
我们可以通过辗转相除的方式,将一个十进制的数子拆分成一个个个位数,并将其统计下来,得到该十进制数为多少位。
int CountNumbers(int num){
int count = 0;
while(num){
num /= 10;
count++;
}
return count;
}
1295. 统计位数为偶数的数字
这道题我们需要对数组进行线性遍历,并通过辗转相除的方式判断每个数是否为偶位数。
代码如下:
int findNumbers(int* nums, int numsSize){
int ret = 0;//统计偶位数的个数
for(int i = 0; i < numsSize; i++){
//统计nums[i]的位数
int n = 0;
//分解
while(nums[i]){
nums[i] /= 10;
n++;
}
//判断
if(n % 2 == 0){
ret++;
}
}
return ret;
}
540. 有序数组中的单一元素
因为相同的数都是相邻的,所以我们可以直接从头开始遍历,每次检查前面一个数据与第二个数据是否相同。
代码如下:
int singleNonDuplicate(int* nums, int numsSize){
int i = 0;
for(; i < numsSize - 1; i += 2){
if(nums[i] != nums[i + 1]){
return nums[i];
}
}
return nums[i];
}
剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
双指针法:
我们可以定义一个数组ret[],定义两个变量left和right分别指向ret的首尾,在对数组nums进行遍历,如果位奇数,则放入ret[left++],为偶数则放入ret[right–]。
如图:
一次类推,我们便可将奇数放在左边,偶数放在右边。
代码如下:
int* exchange(int* nums, int numsSize, int* returnSize){
*returnSize = numsSize;
int* ret = (int*)malloc(sizeof(int) * numsSize);
int left = 0;
int right = numsSize - 1;
for(int i = 0; i < numsSize; i++){
if(nums[i] % 2){
ret[left++] = nums[i];
}
else{
ret[right--] = nums[i];
}
}
return ret;
}
1991. 找到数组的中间位置
分析:
这道题的意思是,找到一个数,该数左边的所有数之和,等于右边所有数之和,如果在左边界,则左边和为0,反之,右边和为0。
我们假设左边和为left,右边和为righ,中间值为mid,所有数和为total,则total = left + right + mid,则right = total - left - mid。
如果left == right,我们可以得到:
int findMiddleIndex(int* nums, int numsSize){
int total = 0;
for(int i = 0; i < numsSize; i++){
total += nums[i];
}
int sum = 0;
for(int i = 0; i < numsSize; i++){
if(2 * sum + nums[i] == total){
return i;
}
sum += nums[i];
}
return -1;
}
724. 寻找数组的中心下标
这道题和前一道题是一样的,解题方法也是一样的
代码如下:
int pivotIndex(int* nums, int numsSize){
int total = 0;
for(int i = 0; i < numsSize; i++){
total += nums[i];
}
int sum = 0;
for(int i = 0; i < numsSize; i++){
if(2 * sum + nums[i] == total){
return i;
}
sum += nums[i];
}
return -1;
}
26. 删除有序数组中的重复项
这道题用快慢双指针的方式
由于nums已成升序,所以该题也大大降低了难度。
思路:
int removeDuplicates(int* nums, int numsSize){
if(numsSize == 0)
return 0;
int slow = 1;
int fast = 1;
while(fast < numsSize){
if(nums[fast] != nums[fast - 1]){
nums[slow] = nums[fast];
slow++;
}
fast++;
}
return slow;
}
1018. 可被 5 整除的二进制前缀
这道题给定一个只包含0和1的数组nums,我们需定义一个数组ret[],ret[i]表示由nums[0],nums[1]…nums[i]组成的二进制数转化为十进制后能否被5整除,能则ret[i] = true,
否则ret[i] = false。
但根据题目给定的范围,我们发现,将其转化为十进制会越界,3000长度的二进制数我们是无法计算的,所以我们需要在计算过程中对其进行mod处理。
代码如下:
bool* prefixesDivBy5(int* nums, int numsSize, int* returnSize){
*returnSize = numsSize;
bool* ret = (bool*)malloc(sizeof(bool) * numsSize);
int dp = 0;
for(int i = 0; i < numsSize; i++){
dp = (dp * 2 + nums[i]) % 5;
ret[i] = dp == 0;
}
return ret;
}
1015. 可被 K 整除的最小整数
这道题简单就简单在数字n只含有1,所以我们只需令n = 1,不断地n *= 10,n += 1,在判断能否整除k即可,但我们还需考虑的是有的数是溢出,有些数能够只含1的数整除的数很大,例如整除23的数的长度为22,也就是1111111111111111111111,这样的数字很明显已经超出我们所能计算的范围,所以我们还需对其进行mod操作。
代码如下:
int smallestRepunitDivByK(int k){
long long n = 1;
int len = 1;
if(k % 2 == 0 || k % 5 == 0){
return -1;
}
while(n < INT_MAX){
if(n % k == 0){
return len;
}
n %= k;
n *= 10;
n += 1;
len++;
}
return -1;
}
1869. 哪种连续子字符串更长
分析:
我们需要分别找出字符‘1’的最大连续长度和字符‘0’的最大连续长度,然后进行比较。
方法步骤:
如果我们要找出‘1’的最大连续长度,我们可以定义两个变量max1和count1,max1用来记录最大连续长度,count1用来计算每段字符‘1’的长度。
当s[i] == '1’时,count1++,当s[i] = '0’时,我们令count1=0,从新计算下一段,并把最长的一段记录到max1中
字符‘0’的长度也是如此。
代码入下:
bool checkZeroOnes(char * s){
int len = strlen(s);
int max1 = 0, max0 = 0;//记录'1'和'0'最长的长度
int count1 = 0, count0 = 0;//计算'1'和'0'每段的长度
for(int i = 0; i < len; i++){
if(s[i] == '0'){
count0++;
}
else{
count0 = 0;
}
if(s[i] == '1'){
count1++;
}
else{
count1 = 0;
}
//将最长的值记录到max0和max1中
max0 = fmax(max0, count0);
max1 = fmax(max1, count1);
}
if(max1 > max0){
return true;
}
return false;
}