字节跳动2022春招笔试详解

题目一:移动最短距离(分析法)

 

 

#include<iostream>
#include<algorithm>
using namespace std;
#include<vector>
//用于记录最短跳跃的n行1列的二维数组,path
//输入的二维数组目标点point
//跳跃的次数k,n行,目标值距离起始点的距离target。

//分析这道题:	假设移动了k次,每次任意地向左或向右移动,那么最终达到的位置实际上就是1,2,3,……,k。

// 这k个整数添加正号或负号后求和的值。如果target<0,可以将这k个数的符号全部取反,这样求和的值为−target>0。

//所以我们可以只考虑target>0 的情况。我们假设移动最小k次,移动总长度为L,能够超越起始点距目标值的距离target

//若此时正好L=target,那k就是我们所求的最小步数,如果L-target为偶数,那此时的最小步数也为k.

//例如起始点为0,目标值为4,  L=1+2+3=6>target=4,  6-4=2为偶数,那我们是不是可以找到一个2/2的数令他为负数,一加一减就为2了

//此时移动为:向左移动1位,向右移动两位,向右移动三位,-1+2+3=4,到达目标值,移动次数为3

//若L-target为奇数时,我们没办法凑出这样的数字,所以我们要使步数k+1,或加2,因为这样必定有一个使L-target为偶数的数,难以理解的话可以看例子

//target为奇数,L为偶数,L-target此时为奇数,不能凑数,我们使k加1来看看,比如L=6,target=5,那么此时k=3,另k +=1,L+k此时等于10。

//10-5=5,还是为奇数,那么在另k+=1,L+k=15,15-5=10,看,此时是不是求出来一个偶数,是不是就又可以凑数了。此时移动次数为5。
class Solution {
public:
	//先求从零点出发寻找的第一个目标值,因为这里我们是0行0列,没办法减去前一个目标值,所以单独拿出来计算
	static vector<vector<int>> search1(vector<vector<int>> point, vector<vector<int>> &path,int &target) {
		target = abs(point[0][0]);                               //abs函数,取模值,因为我们上文分析过,拿正数去计算即可
		int k = 0;
		while (target > 0) {
			k++;
			target -= k;
		}
		int res = target % 2 == 0 ? k : k + 1 + k % 2;          //基础薄弱的话可以去看一下这个三元运算符
		path[0][0] = res;                                       //把求得的移动次数放入到二维数组中,记录答案
		return path;
	}
	static vector<vector<int>> search2(vector<vector<int>> point, vector<vector<int>> &path, int &target, int n) {
		for (int i = 1; i < n; i++) {
			int k = 0;                                     //很关键,因为每次循环找到终点时,k要重新计算,归零
			target = abs(point[i][0] - point[i - 1][0]);   //因为我们要在上一个目标值上进行移动,所以拿当前的目标值减去上次的目标值,就是起始点到终点的距离
			while (target > 0) {
				k++;
				target -= k;
			}
			int result = target % 2 == 0 ? k : k + 1 + k % 2;
			path[i][0] = result;                           //把最小次数挨个放入二维数组中
		}
		return path;
	}
};
int main() {
	int n;
	cin >> n;
	int target = 0;
	vector<vector<int>> point(n, vector<int>(1));
	vector<vector<int>> path(n,vector<int>(1));
	for (int i = 0; i < n; i++) {
		cin >> point[i][0];
	}
	Solution:: search1(point, path, target);
	Solution:: search2(point, path, target, n);
	for (int i = 0; i < n; i++) {
		cout << path[i][0] << endl;
	}
	return 0;
}

测试案例AC如下: 

 

题目二:字母映射数字,求最大得分

 一开始我还想用递归去做,真不知道怎么想的,就下面写的代码我觉得时间复杂度还是有点高,应该可以优化,只不过我没有想到,下述代码时间复杂度O(nlogn),空间复杂度O(n)。

#include<iostream>
#include<algorithm>
using namespace std;
#include<vector>
#include<string>


int MaxSum(int n,int k,string s,vector<int>& vec,int &sum) {
	int m = n - 1;
	for (int i = 0; i < n; i++) {                     //把字母转换成数字放入vec容器中
		vec[i] = s[i] - 'a' + 1;
	}
	sort(vec.begin(), vec.end());
	while (k--) {                                     //求前k个最大数之和
		sum += vec[m--];
	}
	return sum;
}

//n个字母,按k次,最大得分sum,字符串s,把英文字母挨个转换成数字的vec

int main() {
	int n;
	int k;
	int sum = 0;
	cin >> n>>k;
	string s;
	cin >> s;
	vector<int> vec(n);
	MaxSum(n, k, s, vec,sum);
	cout << sum << endl;
	return 0;
}

测试案例如下 :

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

啥也不会的小白123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值