一周刷题回顾

题目1 :存在重复元素
给定一个整数数组,判断是否存在重复元素。
如果任意一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 。
示例 1:
输入: [1,2,3,1]
输出: true
示例 2:
输入: [1,2,3,4]
输出: false
示例 3:
输入: [1,1,1,3,3,4,3,2,4,2]
输出: true

题目来源 : 力扣

自己做的时候,直接暴力枚举, 结果第17个测试用例没通过, 超时了。应该是因为时间复杂度太大了, 为O(n2);

bool containsDuplicate(int* nums, int numsSize){
   int i, j, temp;

   for(i = 0; i < numsSize - 1; i++)
      for(j = 0 ; j < numsSize - 1 -i ; j++)
         if(nums[j] > nums[j + 1])
         {
            temp = nums[j];
            nums[j] = nums[j + 1];
            nums[j + 1] = temp;
         }
    
    for(i = 0; i < numsSize - 1; i++)
        if(nums[i] == nums[i + 1])
            return true;

    return false;

}

然后我看了一下力扣的官方题解,发现使用了一个库函数, 就把时间复杂度降了下来, 不知道为什么,希望有人回我的评论吧。这个解法的时间复杂度为O(nlogn)。


int cmp(const void* _a, const void* _b) {
    int a = *(int*)_a, b = *(int*)_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;
}

题目二:Dota2 参议院
Dota2 的世界里有两个阵营:Radiant(天辉)和 Dire(夜魇)
Dota2 参议院由来自两派的参议员组成。现在参议院希望对一个 Dota2 游戏里的改变作出决定。他们以一个基于轮为过程的投票进行。在每一轮中,每一位参议员都可以行使两项权利中的一项:
1、禁止一名参议员的权利:
2、参议员可以让另一位参议员在这一轮和随后的几轮中丧失所有的权利。

宣布胜利:
如果参议员发现有权利投票的参议员都是同一个阵营的,他可以宣布胜利并决定在游戏中的有关变化。
给定一个字符串代表每个参议员的阵营。字母 “R” 和 “D” 分别代表了 Radiant(天辉)和 Dire(夜魇)。然后,如果有 n 个参议员,给定字符串的大小将是 n。

以轮为基础的过程从给定顺序的第一个参议员开始到最后一个参议员结束。这一过程将持续到投票结束。所有失去权利的参议员将在过程中被跳过。

假设每一位参议员都足够聪明,会为自己的政党做出最好的策略,你需要预测哪一方最终会宣布胜利并在 Dota2 游戏中决定改变。输出应该是 Radiant 或 Dire。

示例 1:
输入:“RD”
输出:“Radiant”
解释:第一个参议员来自 Radiant 阵营并且他可以使用第一项权利让第二个参议员失去权力,因此第二个参议员将被跳过因为他没有任何权利。然后在第二轮的时候,第一个参议员可以宣布胜利,因为他是唯一一个有投票权的人
示例 2:
输入:“RDD”
输出:“Dire”
解释:
第一轮中,第一个来自 Radiant 阵营的参议员可以使用第一项权利禁止第二个参议员的权利
第二个来自 Dire 阵营的参议员会被跳过因为他的权利被禁止
第三个来自 Dire 阵营的参议员可以使用他的第一项权利禁止第一个参议员的权利
因此在第二轮只剩下第三个参议员拥有投票的权利,于是他可以宣布胜利

提示:
给定字符串的长度在 [1, 10,000] 之间.
题目来源:力扣

这个题目用贪心算法可以解决,这是我第一次用贪心的思想解题,我觉得很有意思。
关键在于不管哪一方,只要每个人都把距离自己最近的敌对方的人投死,就可以达到最优的情况。因为如果自己后面有自己的队友,他又把距离他最近的对手投死,那么最佳情况就是自己方一人不死,对方团灭了。或者再不济,也减少住了敌方的进攻机会。
具体做法就是,利用队列,首先使用两个队列radiant和dire分别按照投票顺序存储天辉方和夜魇方每一名议员的投票时间,然后一对一的比较投票顺序,如果那方小就可以把他对应的对手投死,被投死了就出队列,把别人投死了,那么就是加上原先所以人数的数字。

char * predictPartyVictory(char * senate){
   int len = strlen(senate);
   int left_r = 0, left_d = 0;
   int right_r = 0, right_d = 0;
   int radiant[10000], dire[10000];

   for(int i = 0; i < len; i++)
      if(senate[i] == 'R')
         radiant[right_r++] = i;
      else
         dire[right_d++] = i;
    
    while(left_d < right_d && left_r < right_r)
    {
        if(radiant[left_r] < dire[left_d])
            radiant[right_r++] = radiant[left_r] + len;
        else
            dire[right_d++] = dire[left_d] + len;
        left_d++;
        left_r++;
    }

    char *ret = NULL;
    ret = (char *)malloc(sizeof(char) * 8);
    if(left_r < right_r)
        ret = "Radiant";
        else
        ret = "Dire";
    return ret;
}

题目三:最大最小公倍数

问题描述
已知一个正整数N,问从1~N中任选出三个数,他们的最小公倍数最大可以为多少。

输入格式
输入一个正整数N。

输出格式
输出一个整数,表示你找到的最小公倍数。
样例输入
9
样例输出
504

1 <= N <= 106

这个题目,可以用贪心算法来解主要是理解下面的内容

任意大于1的两个相邻的自然数都是互质的.

我们可以知道,当n是奇数时,n 和n-2都是奇数,n-1是偶数,那么他们三个的公约数肯定不是2,而因为这三个数是连续的,所以大于2的数都不可能成为他们或其中任意两个数的公约数了.结果就是他们三个的乘积.

而当n为偶数时,n*(n-1)(n-2)肯定不行了,因为n和n-2都是偶数,那么只能将n-2改成n-3,即n(n-1)*(n-3),如果这三个数两两互质那么肯定就是结果了.

但是因为n和n-3相差3,所以当其中一个数能被3整除时,另一个肯定也可以.而当其中一个不可以时,另一个肯定也不可以.而因为n为偶数,n-3为奇数,所以2不可能成为他俩的公因子。对于大于3的数,肯定就都不可能成为这三个数或者其中任意两个数的公约数了.因此只需再对3进行判断:

如果n能整除3,那么,n(n-1)(n-3)就肯定不行了,因为n和n-3有了公约数3,结果肯定小了,那么就只能继续判下一个即n(n-1)(n-4)而这样n-4又是偶数,不行继续下一个n(n-1)(n-5) = n^3 -6n^2 + 5n 而如果这个可以 那个其值肯定要小于(n-1)(n-2)(n-3) = n^3 -6*n^2+11n-6(对于n>1来说都成立),而(n-1)(n-2)(n-3)由上一个奇数结论可知是一个符合要求的,因此到n-5就不用判断了。直接选答案为(n-1)(n-2)(n-3);

而n不能整除3,那么结果就是n*(n-1)*(n-3),因为n和n-3都不能整除3,此时n-1能不能整除3都无关紧要了.而对于其它数 都是不可能的.

#include <stdio.h>
#include <stdlib.h>
int main()
{
	long long int n,max;
	scanf("%lld",&n);
	if(n<=2)
	{
		max = n;
	}
	else
	{
		if(n%2==0)
		{
			if(n%3==0)
				max = (n-1)*(n-2)*(n-3);
			else max = n*(n-1)*(n-3);
		}
		else max = n*(n-1)*(n-2);
	}
	printf("%lld",max);
	
  system("pause");
  return 0;
}

问题四:2的次幂表示

问题描述
  任何一个正整数都可以用2进制表示,例如:137的2进制表示为10001001。
  将这种2进制表示写成2的次幂的和的形式,令次幂高的排在前面,可得到如下表达式:137=27+23+2^0
  现在约定幂次用括号来表示,即a^b表示为a(b)
  此时,137可表示为:2(7)+2(3)+2(0)
  进一步:7=22+2+20 (2^1用2表示)
  3=2+2^0
  所以最后137可表示为:2(2(2)+2+2(0))+2(2+2(0))+2(0)
  又如:1315=210+28+2^5+2+1
  所以1315最后可表示为:
  2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0)
输入格式
  正整数(1<=n<=20000)
输出格式
  符合约定的n的0,2表示(在表示中不能有空格)
样例输入
137
样例输出
2(2(2)+2+2(0))+2(2+2(0))+2(0)
样例输入
1315
样例输出
2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0)

一边递归一边输出

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int nums[15] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384};

void fun(int n)
{
   int i;

   if(n == 1)
   {
	   printf("2(0)");
	   return ;
   }
	
   for(i = 14; i >= 0; i--)
	   if(nums[i] <= n) break;
   printf("2");

   if(i != 1)
   {
	   printf("(");
	   fun(i);
	   printf(")");
   }
   if(n - nums[i])
   {
	   printf("+");
	   fun(n - nums[i]);
   }
}
int main()
{
   int n;

   scanf("%d", &n);

   fun(n);

   system("pause");
   return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值