刷题 ------ 模拟

文章目录

  • 1.各位相加
  • 2.机器人能否返回原点
  • 3.分糖果 ||
  • 4.奇数值单元格的数目
  • 5.按既定顺序创建目标数组
  • 6.换水问题
  • 7.圆形赛道上经过次数最多的扇区
  • 8.设计停车系统
  • 9.获取生成数组中的最大值
  • 10.比赛中的配对次数
  • 11.基于排列构建数组
  • 12.数组串联
  • 13.字符串转化后的各位数字之和
  • 14.执行操作后的变量值
  • 15.将字符串拆分为若干长度为k的组
  • 16. 将找到的值乘以2
    • (1)模拟(暴力)
    • (2)排序
  • 17.得到0的操作数
  • 18.统计各位数字之后为偶数的整数个数
  • 19.极大极小游戏
  • 20. 计算字符串的数字和
  • 21.使数组中所有元素都等于零
  • 22. 对数组的操作
  • 23.分隔数组中数字的位数
  • 24.从数量最多的堆取走礼物
  • 25.找出数组的串联值
  • 26.递枕头
  • 27.保龄球游戏的获胜者
  • 28.半有序排列
  • 29. 总行驶距离
  • 30 .最大字符串配对数目

模拟也能叫暴力,我是这样理解的,一个问题,首先想到的那个方法(把所有的可能性全部一一遍历出来)。
就比如字符串匹配算法,模拟(暴力)可以使用双for直接做出。
但是这种效率肯定没有KMP匹配算法高。
我在前面刷数组,链表,字符串等等中,其实还是用了很多暴力的方法来做的。
所以此篇我全是用的模拟暴力的求解办法,有些优质的办法也没写出来。

1.各位相加

刷题 ------ 模拟_第1张图片
这道题就是给一个数num,然后去将其的每一位都相加起来,然后再将其每一位相加,直到它变成了一个1位数位置。

int addDigits(int num)
{
    while(num >= 10)
    {   
        int tmp = num,sum = 0;
        //求每一位的总和
        while(tmp != 0)
        {
            sum += (tmp % 10);
            tmp /= 10;
        }
        //将num更新成当前每一位的总和
        num = sum;
    }

    return num;
}

2.机器人能否返回原点

刷题 ------ 模拟_第2张图片

  • 拿x和y去充当(0,0)的坐标
  • 然后遍历字符串,对x和y进行其对应的加减即可
bool judgeCircle(char* moves)
{
    int len = strlen(moves);
    if(len % 2 != 0)
    {
        return false;
    }
    int i, x = 0, y = 0;
    for (i = 0; i < len; i++)
    {
        if(moves[i] == 'U')
        {
            y++;
        }
        else if(moves[i] == 'R')
        {
            x++;
        }
        else if(moves[i] == 'D')
        {
            y--;
        }
        else
        {
            x--;
        }
    }

    return x == 0 && y == 0;
}

3.分糖果 ||

刷题 ------ 模拟_第3张图片

  • 由题可以知道,循环的终止条件一定是candies为0。
  • 然后孩子的变化是一组一组的变,
  • 而分配的糖果则是1,2,3,4,5,6,…………无线递增,直到没有糖果。

有了上面的这三个条件,代码如下:

int* distributeCandies(int candies, int num_people, int* returnSize)
{
    int* ans = (int*)calloc(num_people,sizeof(int));
    *returnSize = num_people;
    int i = 0,tmp = 1;
    while(candies > 0)
    {   
        //总糖果个数大于当前应该发的糖果个数
        if(candies < tmp)
        {
            //将当前所剩的糖果分给当前孩子
            ans[i] += candies;
            break;
        }
        else
        {
            ans[i++] += tmp;
        }
        //分配完一组回去接着分配
        if(i >= num_people)
        {
            i = 0;
        }
        candies -= tmp++;
    }

    return ans;
}

4.奇数值单元格的数目

刷题 ------ 模拟_第4张图片

  • 创建一个m*n的matrix的矩阵全部初始化成 0
  • 然后去遍历所给的indices中的下标,对矩阵进行自增
  • 最后遍历矩阵,得出奇数即可

//给x y 所对应的行和列全部增1
void PlusOne(int x, int y,int** matrix, int row, int col)
{
    int i;
    //行
    for (i = 0; i < col; i++)
    {
        matrix[x][i]++;
    }

    //列
    for (i = 0; i < row; i++)
    {
        matrix[i][y]++;
    }
}


int oddCells(int m, int n, int** indices, int indicesSize, int* indicesColSize)
{
    int i,j,count = 0;
    //创建矩阵
    int** matrix = (int**)malloc(sizeof(int*) * m);
    for (i = 0 ; i < m; i++)
    {
        matrix[i] = (int*)calloc(n,sizeof(int));
    }

    //处理矩阵自增
    for (i = 0; i < indicesSize; i++)
    {
        PlusOne(indices[i][0],indices[i][1],matrix,m,n);
    }

    //统计矩阵中的奇数
    for (i = 0; i < m; i++)
    {
        for (j = 0; j < n; j++)
        {
            if(matrix[i][j] % 2 != 0)
            {
                count++;
            }
        }
    }

    return count;
}

5.按既定顺序创建目标数组

刷题 ------ 模拟_第5张图片

  • 对两个数组同时进行遍历,获取其中的下标(in),以及下标对应的值(val)
  • 然后判断当前的所插入的值位置,是否需要挪动。
  • 随后在对应位置,插入值即可
int* createTargetArray(int* nums, int numsSize, int* index, int indexSize, int* returnSize)
{
    int* ans = (int*)malloc(sizeof(int) * numsSize);
    *returnSize = numsSize;
    int i,size = 0;
    for (i = 0; i < numsSize; i++)
    {
        int in = index[i],val = nums[i];
        for (int j = size; j > in; j--)
        {
            ans[j] = ans[j-1];
        }
        ans[in] = val;
        size++;
    }

    return ans;
}

6.换水问题

刷题 ------ 模拟_第6张图片

  • 兑换完一瓶后,这瓶喝掉后,也是空瓶
int numWaterBottles(int numBottles, int numExchange)
{
    int count = numBottles,emptyBottles = numBottles; //count 喝掉的 empty 空的
    while(emptyBottles - numExchange >= 0)
    {
        //当前的空水瓶,可以兑换一瓶
        count++;
        emptyBottles -= (numExchange-1);
    }
    return count;
}

7.圆形赛道上经过次数最多的扇区

刷题 ------ 模拟_第7张图片

  • 因此此题的答案仅与起点和终点相关。从起点沿着逆时针方向走到终点的这部分扇区,就是经过次数最多的扇区。
  • 对于起点和终点有两种情况
  • 第一种:起点比终点小(等于),直接从起点遍历到终点即可。
  • 第二种:起点比终点大,需要对其进行对应的取值。
int* mostVisited(int n, int* rounds, int roundsSize, int* returnSize)
{
    int* ans = (int*)malloc(sizeof(int) * n);
    int i,index = 0;
    int begin = rounds[0],end = rounds[roundsSize-1];
    if(begin <= end)
    {
        for (i = begin; i <= end; i++)
        {
          ans[index++] = i;
        }
    }
    else
    {
        //起点比终点大
        for (i = 1; i <= n; i++)
        {
            if(i <= end || i >= begin)
            {
                ans[index++] = i;
            }
        }
    }
    *returnSize = index;
    return ans;
}   

8.设计停车系统

刷题 ------ 模拟_第8张图片

  • 。。。。。。。。。。。。。。。。。。。。。。。。。
typedef struct
{
    int* map;
} ParkingSystem;


ParkingSystem* parkingSystemCreate(int big, int medium, int small)
{
    ParkingSystem* obj = (ParkingSystem*)malloc(sizeof(ParkingSystem));
    obj -> map = (int*)calloc(4,sizeof(int));
    obj -> map[1] = big;
    obj -> map[2] = medium;
    obj -> map[3] = small;

    return obj;
}

bool parkingSystemAddCar(ParkingSystem* obj, int carType)
{
    if(obj -> map[carType] == 0)
    {
        return false;
    }

    obj -> map[carType]--;
    return true;
}

void parkingSystemFree(ParkingSystem* obj)
{
    free(obj -> map);
    free(obj);
}


9.获取生成数组中的最大值

刷题 ------ 模拟_第9张图片

  • 先给第一个数值赋为1
  • 此后就可以动态的去生成到n的所有值了
  • 索引为偶数的话,取当前索引除2的值
  • 为奇数的话,取当前索引除2的值和后一个的值

在这里插入图片描述

上图中,如果i为偶数的话,i%2永远是0,所以不用考虑后半段的值

int getMaximumGenerated(int n)
{
    if(n == 0)
    {
        return 0;
    }

    int* nums = (int*)malloc(sizeof(int) * (n+1));
    nums[1] = 1;
    int max = nums[1],i;
    for (i = 2; i <= n; i++)
    {
        nums[i] = nums[i/2] + (i % 2) * nums[i/2+1];
        if(max < nums[i])
        {
            max = nums[i];
        }
    }

    return max;
}

10.比赛中的配对次数

刷题 ------ 模拟_第10张图片

  • 配对次数是总队伍数进行折半。
  • 总队伍数如果是偶数,那么正好就是折半后的队伍
  • 如果是奇数的话,就当全部队伍随机减去一给变成偶数,最后再加回来即可
int numberOfMatches(int n)
{
    int ans = 0;
    while(n != 1)
    {
        int tmp = n / 2;
        ans += tmp;
        //判断奇偶
        if(n % 2 != 0)
        {
            n = tmp + 1;
        }
        else
        {
            n = tmp;
        }
    }
    return ans;
}

11.基于排列构建数组

刷题 ------ 模拟_第11张图片

  • 额。。。。还真是模拟就好了,答案就在题目中
int* buildArray(int* nums, int numsSize, int* returnSize)
{
    int* ans = (int*)malloc(sizeof(int) * numsSize);
    *returnSize = numsSize;
    int i;
    for (i = 0; i < numsSize; i++)
    {
        ans[i] = nums[nums[i]];
    }    

    return ans;
}   

12.数组串联

刷题 ------ 模拟_第12张图片

  • 在当前数组的后面追加一份当前数组。
int* getConcatenation(int* nums, int numsSize, int* returnSize)
{
    nums = (int*)realloc(nums,sizeof(int) * 2 * numsSize);
    *returnSize = 2 * numsSize;
    for (int i = 0; i < numsSize; i++)
    {
        nums[i + numsSize] = nums[i];
    }    

    return nums;
}

13.字符串转化后的各位数字之和

刷题 ------ 模拟_第13张图片

  • 首先遍历一遍字符串,将其对应的各个字母转化为相应的数字,同时写入一个字符数组中去
  • (将字母字符串转化为数字字符串)
  • 然后在循环k次,每次中进行求每一位数的总和
  • 最后将字符串转化为数字
int getLucky(char* s, int k)
{
    int len = strlen(s);
    char* ans = (char*)malloc(sizeof(char) * (2 * len + 1));
    int i,pos = 0;
    //将字母转化为数字
    for (i = 0; i < len; i++)
    {
        pos += sprintf(ans + pos,"%d",s[i] - 'a' + 1);
    }
    //数字的长度
    int lenAns = pos;
    //循环k次
    for (i = 0; i < k; i++)
    {
        //求出每次的值
        int sum = 0;
        for (int j = 0; j < lenAns; j++)
        {
            sum += ans[j] - '0';
        }

        //重新写入ans中并且更新长度
        lenAns = sprintf(ans,"%d",sum);
    }
    
    return atoi(ans);
}

14.执行操作后的变量值

刷题 ------ 模拟_第14张图片

  • 不管是++X还是X++,你切记,你二个字符,永远是 +
  • 那么ok了。
int finalValueAfterOperations(char** operations, int operationsSize)
{
    int i,ans = 0;
    for (i = 0; i < operationsSize; i++)
    {
        if(operations[i][1] == '+')
        {
            ans++;
        }
        else
        {
            ans--;
        }
    } 
    return ans;
}

15.将字符串拆分为若干长度为k的组

刷题 ------ 模拟_第15张图片

  • 就遍历一边s字符串,每遍历k个字符,就拷贝到ans中
  • 如果最后还有剩余的字符,那么index一定不是0。
  • 然后将其补全fill即可
char** divideString(char* s, int k, char fill, int* returnSize)
{
    int len = strlen(s);
    char** ans = (char**)malloc(sizeof(char*) * ((len/k) + 1));
    int i,size = 0;   //size ~ ans 的大小
    //每一段的字符串
    char* tmp = (char*)malloc(sizeof(char) * (k+1));
    int index = 0;
    //
    for (i = 0; i < len; i++)
    {
        tmp[index++] = s[i];
        if(index == k)
        {
            tmp[index] = '\0';
            ans[size] = (char*)malloc(sizeof(char) * (k + 1));
            strcpy(ans[size++],tmp);
            index = 0;
            count = 0;
        }
    }
    //如果是正好全部分配完成的话,index == 0
    if(index != 0)
    {
        while(index < k)
        {
            tmp[index++] = fill;
        }
        tmp[index] = '\0';
        ans[size] = (char*)malloc(sizeof(char) * (k + 1));
        strcpy(ans[size++],tmp);
    }

    *returnSize = size;
    return ans;
}

16. 将找到的值乘以2

刷题 ------ 模拟_第16张图片

(1)模拟(暴力)

  • 就直接对数组进行遍历
  • 每一次如果能够找到original然后对其翻倍,因为其的大小顺序不一致,所以得再重头开始找。
int findFinalValue(int* nums, int numsSize, int original)
{
    int i;
    for (i = 0; i < numsSize; i++)
    {
        if(nums[i] == original)
        {
            original *= 2;
            i = -1;
        }
    }

    return original;
}

(2)排序

接着上面的,因为不知道顺序,所以从头开始找,那么进行排序即可解决这个问题。

int cmp_int(const void* x, const void* y)
{
    return *(int*)x - *(int*)y;
}

int findFinalValue(int* nums, int numsSize, int original)
{
    int i;
    qsort(nums,numsSize,sizeof(nums[0]),cmp_int);
    for (i = 0; i < numsSize; i++)
    {
        if(nums[i] == original)
        {
            original *= 2;
        }
    }

    return original;
}

17.得到0的操作数

刷题 ------ 模拟_第17张图片

恩。。。。。。。。。

int countOperations(int num1, int num2)
{
    int count = 0;
    while(num1 != 0 && num2 != 0)
    {
        if(num1 >= num2)
        {
            num1 -= num2;
        }
        else
        {
            num2 -= num1;
        }
        count++;
    }
    return count;
}

18.统计各位数字之后为偶数的整数个数

刷题 ------ 模拟_第18张图片

  • 之前刷题中,我记得有一道是肯定是和求出这个数的每一位的总和有关的题,所以我在下方利用了一个DigitSum的函数
  • 然后对其1~n进行遍历就,统计满足条件的次数即可
int DigitSum(int num)
{
    int sum = 0;
    while(num != 0)
    {
        sum += (num % 10);
        num /= 10;
    }

    return sum;
}


int countEven(int num)
{
    int count = 0;
    for (int i = 1; i <= num; i++)
    {
        int tmp = DigitSum(i);
        if(tmp % 2 == 0)
        {
            count++;
        }
    }
    return count;
}

19.极大极小游戏

刷题 ------ 模拟_第19张图片

  • 可以直接在数组中进行修改,在空间上有了优化。
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#define MIN(x,y) ((x) > (y) ? (y) : (x))

int minMaxGame(int* nums, int numsSize)
{
    while(numsSize != 1)
    {
        numsSize /= 2;  //折半
        for (int i = 0; i < numsSize; i++)
        {
            if(i % 2 == 0)
            {
            	//偶数下标
                nums[i] = MIN(nums[2 * i],nums[2 * i + 1]);
            }
            else
            {
            	//奇数下标
                nums[i] = MAX(nums[2 * i],nums[2 * i + 1]);
            }
        }
    }

    return nums[0];
}

20. 计算字符串的数字和

刷题 ------ 模拟_第20张图片

  • 注意整体的循环条件是新字符串的长度必须小于等于所给的k
  • 然后就是对每一段(k)进行求和即可。
char* digitSum(char* s, int k)
{
    int len = strlen(s);
    //k
    while(len > k)
    {
        int i, pos = 0;
        //存储新构成的字符串
        char* tmp = (char*)malloc(sizeof(char) * (len + 1));
        for (i = 0; i < len; i += k)
        {
            //size 不能越界,发现比i + k 大 的话,选择len就好了
            int sum = 0,size = (i + k) < len ? i + k : len;
            for (int j = i; j < size; j++)
            {
                sum += s[j] - '0';
            }
            pos += sprintf(tmp + pos, "%d",sum);
        }
        s = tmp;
        len = strlen(s);
    }

    return s;
}

21.使数组中所有元素都等于零

刷题 ------ 模拟_第21张图片

  • 首先对数组进行升序排序。
  • 然后数组中第一个不为0的数据,就是最小的那个
  • 从此处开始,依次往后减去。
  • 直到遍历完数组位置

int cmp_int(const void* x, const void* y)
{
    return *(int*)x - *(int*)y;
}


int minimumOperations(int* nums, int numsSize)
{
    int count = 0,i;
    qsort(nums,numsSize,sizeof(int),cmp_int);
    //升序排序后
    for (i = 0; i < numsSize; i++)
    {
        //第一个不为0的位置就是
        if(nums[i] != 0)
        {
            //依次向后减去
            int tmp = nums[i];
            for (int j = i; j < numsSize; j++)
            {
                nums[j] -= tmp;
            }
            count++;
        }
    }

    return count;
}

22. 对数组的操作

刷题 ------ 模拟_第22张图片

  • 对于数组进行遍历,然后如果发现符合nums[i] == nums[i+1]的时候,就去更改其值
  • 双指针,拿一个 j 来记录当前0元素的位置。
int* applyOperations(int* nums, int numsSize, int* returnSize)
{
    int i,j = 0;
    for (i = 0; i < numsSize; i++)
    {
        if( i + 1 < numsSize && nums[i] == nums[i + 1])
        {
            nums[i] *= 2;
            nums[i + 1] = 0;
        }

        if(nums[i] != 0)
        {
            int tmp = nums[i];
            nums[i] = nums[j];
            nums[j++] = tmp;
        }
    }
    *returnSize = numsSize;
    return nums;
}

23.分隔数组中数字的位数

刷题 ------ 模拟_第23张图片

  • 首先得会将一个数的每一位拆分出来
  • 然后将其拆分出来的每一位依次放入ans中即可
  • 大概就是下面这么一张图
    刷题 ------ 模拟_第24张图片
int* separateDigits(int* nums, int numsSize, int* returnSize)
{
    int* ans = (int*)malloc(sizeof(int) * 1000000);
    int i, size = 0;
    for (i = 0; i < numsSize; i++)
    {
        int x = nums[i];
        int tmp[6] = {0},index = 0; // 6 ~ (10^5)位数 
        while(x != 0)
        {
            tmp[index++] = x % 10;
            x /= 10;

        }
        for (int j = index - 1; j >= 0; j--)
        {
            ans[size++] = tmp[j];
        }
    }   
    *returnSize = size;
    return ans;
}

24.从数量最多的堆取走礼物

刷题 ------ 模拟_第25张图片

  • 找出当前数组中的最大那个数
  • 对其进行开平方
  • 然后执行k次
  • 最后统计数组总和即可
int cmp_int(const void* x, const void* y)
{
    return *(int*)x - *(int*)y;
}


long long pickGifts(int* gifts, int giftsSize, int k)
{
    long long ans = 0;
    while(k > 0)
    {
        qsort(gifts,giftsSize,sizeof(int),cmp_int);
        gifts[giftsSize-1] = sqrt(gifts[giftsSize-1]);
        k--;
    }
    for (int i = 0; i < giftsSize; i++)
    {
        ans += gifts[i];
    }

    return ans;
}
//25 64 9 4 100
//25 64 9 4 10  
//25 8  9 4 10  
//5  8  9 4 10  
//5  8  9 4 3   
// 5+8+9+4+3=29

25.找出数组的串联值

刷题 ------ 模拟_第26张图片

  • 双指针以前一后去得到两个数
  • 将两个数链接在一个字符串中
  • 将其转化位数字
  • 加入ans中即可
long long findTheArrayConcVal(int* nums, int numsSize)
{
    long long ans = 0;
    int i = 0,j = numsSize -1;
    while(i < j)
    {
        char* tmp = (char*)malloc(sizeof(int) * (5 + 1));     //10*10*10*10=10000
        int pos = 0;
        pos += sprintf(tmp + pos,"%d",nums[i++]);
        pos += sprintf(tmp + pos,"%d",nums[j--]);
        ans += atoi(tmp);
    }
    if(i == j)
    {
        ans += nums[i];
    }

    return ans;
}

26.递枕头

刷题 ------ 模拟_第27张图片

  • 首先得知道两点
  • 如果 time / (n - 1) 是奇数 就证明是从终点向起点传递
  • 如果 time / (n - 1) 是偶数 就证明是从起点向终点传递
int passThePillow(int n, int time)
{
    if((time / (n-1)) % 2 == 0)
    {
        //偶数回到起点
        return (time % (n-1)) + 1;
    }
    else
    {
        //奇数,从终点往回退
        return n - (time % (n-1));
    }
}

27.保龄球游戏的获胜者

刷题 ------ 模拟_第28张图片

  • 就求出两个数组的总和,注意如果前两轮有10分的话当前轮翻倍就好了。
int isWinner(int* player1, int player1Size, int* player2, int player2Size)
{
    int sum1 = 0, sum2 = 0;
    int i;
    for (i = 0; i < player1Size; i++)
    {
        if((i - 1 >= 0 && player1[i-1] == 10) || ((i - 2 >= 0) && player1[i-2] == 10))
        {
            sum1 += player1[i] * 2;
        }
        else
        {
            sum1 += player1[i];
        }

        if((i - 1 >= 0 && player2[i-1] == 10) || ((i - 2 >= 0) && player2[i-2] == 10))
        {
            sum2 += player2[i] * 2;
        }
        else
        {
            sum2 += player2[i];
        }

    }

    if(sum1 == sum2)
    {
        return 0;
    }

    return sum1 > sum2 ? 1 : 2;
}

28.半有序排列

刷题 ------ 模拟_第29张图片

  • 一个数组,只要满足第一个是1,最后一个是numsSize就是半有序排序
  • 所以我们只需要找到当前数组中1所对应的下标,和numsSize所对应的下标
  • 当找到这俩的下标的时候,
  • 因为minIndex要往左边移动(0的位置)
  • 而maxIndex要往右边移动(numsSize - 1的位置)
  • 所以minIndex - 0 就是1移动回0位置的次数,反之numsSize也是一样的

刷题 ------ 模拟_第30张图片

  • 要注意一个特别的情况,就是minIndex > maxIndex
  • 这种情况,就得先向他俩互换,然后再进行运算
int semiOrderedPermutation(int* nums, int numsSize)
{
    int maxIndex,minIndex,i,count = 0;
    for (i = 0; i <numsSize; i++)
    {
        if(nums[i] == 1)
        {
            minIndex = i;
        }

        if(nums[i] == numsSize)
        {
            maxIndex = i;
        }
    }
    int swap = 0;
    if(minIndex > maxIndex)
    {
        //公式
        swap = 2 * (minIndex - maxIndex) - 1;
        int tmp = minIndex;
        minIndex = maxIndex;
        maxIndex = tmp;
    }

    //小的移动到0 大的移动到numsSize - 1
    count = swap + (minIndex - 0) + (numsSize - 1 - maxIndex);
    return count;
}

29. 总行驶距离

刷题 ------ 模拟_第31张图片

  • 直接模拟就好了
  • 用满5升,并且备用有油。
int distanceTraveled(int mainTank, int additionalTank)
{
    int count = 0;  //记录使用了多少升,每5升可从备用中换取1升
    while(mainTank != 0)
    {   
        mainTank--;
        count++;
        //保证用了5升,并且备用油箱有油
        if(count % 5 == 0 && additionalTank != 0)
        {
            mainTank++;
            additionalTank--;
        }
    }

    return count * 10;
}

30 .最大字符串配对数目

刷题 ------ 模拟_第32张图片

  • 你切记,看完题目!
    刷题 ------ 模拟_第33张图片
int maximumNumberOfStringPairs(char ** words, int wordsSize)
{
    int i, ans = 0;
    for (i = 0; i < wordsSize; i++)
    {
        for (int j = i + 1; j < wordsSize; j++)
        {
            if(words[i][0] == words[j][1] && words[i][1] == words[j][0])
            {
                ans++;
                break;
            }
        }
    }


    return ans;
}

如果范围不是2的话,反转一下字符串再去比较就好了

你可能感兴趣的:(c语言,算法,leetcode)