变态跳台阶、快到碗里来
题目要求:
<1>.一只青蛙,一次可以跳一级台阶,或者两级,或者跳n级
<2>.输出青蛙跳上n级台阶的方法数
解题思路:
<1>.状态转移方程:F(n)=F(n-1)+F(n-2)+F(n-3)…+F(1)
<2>.F(n-1)=F(n-2)+F(n-3)…+F(1)
<3>.F(n)=2F(n-1)
<4>.返回结果F(n)
代码示例:
#include<vector>
class Solution
{
public:
int jumpFloorII(int number)
{
//动态规划问题
//状态:青蛙调到台阶上的方法数
//初始化
vector<int> F(number+1);
F[0]=1;
F[1]=1;
F[2]=2;
//状态转移方程:F(n)=F(n-1)+F(n-2)+F(n-3)...+F(1)
//F(n-1)=F(n-2)+F(n-3)...+F(1)
//F(n)=2F(n-1)
for(int i=3;i<=number;++i)
{
F[i] = 2 * F[i - 1];
}
//返回结果:F(n)
return F[number];
}
};
优化写法:
class Solution
{
public:
int jumpFloorII(int number)
{
return 1<<(number-1);
}
};
题目要求:
<1>.猫的身长比碗的周长短,就会把自己放到碗里去
<2>.可以放进去输出Yes,不能输出No
解题思路:
<1>.就是考察取值范围,long double可以取到2^128位,不会溢出
<2>.然后就没然后了…
代码示例:
#include<iostream>
using namespace std;
int main()
{
long double n,r;
while(cin>>n>>r)
{
if(n<=(2*3.14*r))
{
cout<<"Yes"<<endl;
}
else
{
cout<<"No"<<endl;
}
}
return 0;
}
不用减减乘除做加法、三角形
题目要求:
两个数,不使用运算符号完成相加
解题思路:
<1>.两个数异或:相当于每一位相加,而不考虑进位;
<2>.两个数相与,并左移一位:相当于求得进位;
<3>.少写了一个=号导致num1的左移没有成功,0%通过…细心!!
代码示例:
class Solution {
public:
int Add(int num1, int num2)
{
//位运算,A进位,B结果
while(num1!=0)
{
int tmp=num2;
num2=num1^num2;
num1=num1&tmp;
num1<<=1;
}
return num2;
}
};
题目要求:
<1>.输入三个数a,b,c
<2>.取值范围都是10^100;
<3>.能组成三角形输出Yes,不能输出No
解题思路:
long double满足范围,但是不是很严谨
代码示例:
#include<iostream>
using namespace std;
int main()
{
long double a, b, c;
while (cin >> a >> b >> c)
{
if ((a + b > c) && (a + c > b) && (b + c > a))
{
cout << "Yes" << endl;
}
else
{
cout << "No" << endl;
}
}
system("pause");
return 0;
}
奇数位放奇数偶数位放偶数、猴子分桃
题目要求:
<1>.输入:数组arr,长度大于2
<2>.将arr调整成奇数位上都是奇数或者偶数位上都是偶数
解题思路:
<1>.快慢指针类似的方法,一个先放在偶数位起点,一个放在奇数位起点,如果角色不对,互换
<2>.如果对着,就找下一个位置,都是+=2的步数
<3>.但是,测试用例就是通不过,我很想知道如何排出示例中的顺序的?
代码示例:
class Solution
{
public:
/**
* 奇数位上都是奇数或者偶数位上都是偶数
* 输入:数组arr,长度大于2
* len:arr的长度
* 将arr调整成奇数位上都是奇数或者偶数位上都是偶数
*/
void oddInOddEvenInEven(vector<int>& arr, int len)
{
int i = 0;
int j = 1;
while (i<len&&j<len)
{
if (arr[i] % 2 == 0)
{
i += 2;
continue;
}
if (arr[j] % 2 == 1)
{
j += 2;
continue;
}
if (arr[i] % 2 != 0 && arr[j] % 2 == 0)
{
swap(arr[i], arr[j]);
i += 2;
j += 2;
}
}
}
};
题目要求:
老猴子辛苦了一辈子,给那群小猴子们留下了一笔巨大的财富——一大堆桃子。老猴子决定把这些桃子分给小猴子
第一个猴子来了,它把桃子分成五堆,五堆一样多,但还多出一个.它把剩下的一个留给老猴子自己拿走其中的一堆
第二个猴子来了,它把桃子分成五堆,五堆一样多,但又多出一个.它把多出的一个留给老猴子自己拿走其中的一堆
后来的小猴子都如此照办.最后剩下的桃子全部留给老猴子
这里有n只小猴子,请你写个程序计算一下在开始时至少有多少个桃子,以及最后老猴子最少能得到几个桃子
解题思路:
<1>.这是编程题?这是数学题
<2>.我承认我没做出来,我看的别人的方法,一顿推导
<3>.结论是桃子总数满足5^n-4可以满足题目说的最后剩下的要是整数
<4>.老猴子得到的最后剩下的和每个猴子给的一个(总数n),加起来结果化简为4^n+n-4
代码示例:
#include<iostream>
#include<math.h>
using namespace std;
int main()
{
int n;
while (cin >> n)
{
if (n == 0)
{
break;
}
cout << (long)pow(5, n) - 4 << " " << (long)pow(4, n) + n - 4 << endl;
}
system("pause");
return 0;
}
正数数组的最小不可组成和、找假币
题目要求:
给定一个全是正数的数组arr,定义一下arr的最小不可组成和的概念:
1,arr的所有非空子集中,把每个子集内的所有元素加起来会出现很多的值,其中最小的记为min,最大的记为max;
2,在区间[min,max]上,如果有一些正数不可以被arr某一个子集相加得到,那么这些正数中最小的那个,就是arr的最小不可组成和;
3,在区间[min,max]上,如果所有的数都可以被arr的某一个子集相加得到,那么max+1是arr的最小不可组成和;
举例:
arr = {3,2,5} arr的min为2,max为10,在区间[2,10]上,4是不能被任何一个子集相加得到的值中最小的,所以4是arr的最小不可组成和;
arr = {3,2,4} arr的min为2,max为9,在区间[2,9]上,8是不能被任何一个子集相加得到的值中最小的,所以8是arr的最小不可组成和;
arr = {3,1,2} arr的min为1,max为6,在区间[2,6]上,任何数都可以被某一个子集相加得到,所以7是arr的最小不可组成和;
请写函数返回arr的最小不可组成和
解题思路:
<1>.首先先把区间找到,Min就是数组中最小的数字,Max是所有数字相加的和,大写是为了和max方法区分开
<2>.转换为动态规划的01背包问题,考虑第i个值是否使用
<3>.写过很多次的状态转移方程F(j)=max(F[j],F[j-a[i]]+a[i])
<4>.最后for循环结束也要有一个return i
代码示例:
#include<vector>
#include<algorithm>
class Solution
{
public:
/**
* 正数数组中的最小不可组成和
* 输入:正数数组arr
* 返回:正数数组中的最小不可组成和
*/
int getFirstUnFormedNum(vector<int> arr, int len)
{
int i, j;
int Min = arr[0], Max = 0;
for (i = 0; i < len; i++)
{
Max += arr[i];
if (arr[i] < Min)
{
Min = arr[i];
}
}
//找到区间[min,max]
//状态转移方程:F(j)=max(F[j],F[j-a[i]]+a[i])
vector<int> dp(Max + 1, 0);
for (i = 0; i < len; i++)
{
for (j = Max; j >= arr[i]; j--)
{
dp[j] = max(dp[j], dp[j - arr[i]] + arr[i]);
}
}
for (i = Min; i <= Max; i++)
{
//找到不可以由区间中加出来的就返回
if (i != dp[i])
{
return i;
}
}
return i;
}
};
题目要求:
给一堆硬币,让你找出假币需要的次数
解题思路:
<1>.不给硬币,就不玩了,break,否则格式(输出)错误
<2>.一个硬币,0次!不需要称天平
<3>.两个硬币,1次,三个,也是一次,天平上两个如果有假币,结束,没有就是没称的那个是假的
<4>.硬币数大于三个,反正都分成三份,是3的倍数就是/3,不是就是/3再+1
<5>.每分一次就称量计数+1,大于三个硬币count是从1开始计数的
代码示例:
#include<iostream>
using namespace std;
int main()
{
int n;
while (cin >> n)
{
//4--->3 1--->1 1 1 1
if(n==0)
{
break;
}
else if (n == 1)
{
cout << 0 << endl;
}
else if (n <= 3)
{
cout << 1 << endl;
}
else
{
//这里已经需要1次了
int count = 1;
while (n > 3)
{
//不管怎么说,都分成三份
if (n % 3 == 0)
{
n = n / 3;
}
else
{
n = n / 3 + 1;
}
//每分一次就加一
count++;
}
cout << count << endl;
}
}
system("pause");
return 0;
}
最难的问题、因子个数
题目要求:
<1>.每个字母对应的明文都是后五位
<2>.ABCDEFGHIJKLMNOPQRSTUVWXYZ
VWXYZABCDEFGHIJKLMNOPQRSTU
<3>.输入一个字符串,输出密码
解题思路:
<1>.两个字符串,输入的串去拿正常的下标
<2>.新串+=密码串[下标]
代码示例:
#include<iostream>
#include<string>
using namespace std;
int main()
{
string S("VWXYZABCDEFGHIJKLMNOPQRSTU ");
string s("ABCDEFGHIJKLMNOPQRSTUVWXYZ ");
string A;
while (getline(cin, A))
{
string Res;
for (int i = 0; i < A.size(); ++i)
{
int res = s.find(A[i]);
Res += S[res];
}
cout << Res << endl;
}
system("pause");
return 0;
}
题目要求:
<1>.输入一个数
<2>.输出其因子个数
解题思路:
<1>.从2开始遍历到n的开方,一直n/=i,如果不能整除,说明还有别的因子
<2>.如果循环结束,n!=1,说明剩下的这个数也是因子,计数要加1
<3>.36->18 2->9 2 2->3 3 2 2
代码示例:
#include <iostream>
#include<math.h>
using namespace std;
int main()
{
int n, ret;
while (cin >> n)
{
ret = 0;
for (int i = 2; i <= sqrt(n); i++)
{
if (n%i == 0)
{
while (n%i == 0)
{
n = n / i;
}
ret++;
}
}
if (n != 1)
{
ret++;
}
cout << ret << endl;
}
system("pause");
return 0;
}