浪潮笔试之搬石头

搬石头排序

题目:沙滩摆放着一排大小不一的球形石头,已知第i个石头的半径为ri,不存在两个石头半径相等。现要求通过移动石头使摆放的石头从左往右半径递增。每次可选择一块石头,并把它放在剩下n-1块石头的最左边或最右边。求最少操作次数。
输入:第一行一个整数n,表示石头个数。(1 <= n <= 100000).第二行n个整数,表示从左往右石头的半径r1,r2,…,rn( 1<= ri <= n)。保证不存在两个不同的石头半径相等。
输出:最少操作次数。
样例输入
6
3 2 1 4 6 5
样例输出
3

分析

实则题目就等于求出最长升序子字符串,但因为题目加了限制条件:每次可选择一块石头,并把它放在剩下n-1块石头的最左边或最右边。所以转变为需要我们去求出最长真升序子字符串,即相对位置与排序完的字符串对应的字符串。比如3 2 1 4 6 5,排完序后:1 2 3 4 5 6,对比两个子字符串,发现原字符串3 4 5排完序相对位置没变,所以3 4 5即为原字符串的最长真升序字符数组。找到最长真升序字符数组后,剩下有多少个其他字符就应该挪动多少次。

参考代码

int MinMoveStone(int n, vector<int> &num)
{
	if (n <= 0) return -1; //边界值判定
	vector<int> oderedNum = num;
	sort(oderedNum.begin(), oderedNum.end());
	int maxStrLen = -1; //设置初始值
	int curr = 1; //如果未找到相应真升序子字符串,则为任何某字符本身
	auto itPre = oderedNum.begin();
	auto it = itPre + 1;
	int m = -1; int k = -1;
	while (it != oderedNum.end())
	{
		for (int i = 0; i < n; ++i)
		{
			if (num[i] == *itPre)
				m = i;
			if (num[i] == *it)
				k = i;
			if (m != -1 && k != -1)
				break;
		}
		if (m < k) //判断是否满足真升序字符串条件
			++curr;
		if (curr > maxStrLen)
			maxStrLen = curr;
		m = -1;
		k = -1;
		++itPre;
		++it;
	}
	return n - maxStrLen; //返回剩下的字符个数
}
时间复杂度:遍历字符数组消耗o(n),由于每次需要找到两个字符的对应下标,所以还需花费o(n)时间,总时间复杂度为o(n^2)。
空间复杂度:用了额外的排序后数组来找寻真升序子字符串,总空间复杂度为o(n)。
改进:可以考虑用Hash存取原数组下标,这样时间复杂度降为:o(n),空间复杂度还是:o(n)。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值