题目描述:
沙滩摆放着一排大小不一的球形石头,已知第i个石头的半径为ri,不存在两个石头半径相等。现要求通过移动石头使摆放的石头从左往右半径递增。每次可选择一块石头,并把它放在剩下n-1块石头的最左边或最右边。求最少操作次数。
输入描述:
第一行一个整数n,表示石头个数(1 <= n <= 100000)。第二行n个整数,表示从左往右石头的半径r1,r2,…,rn( 1<= ri <= n)。保证不存在两个不同的石头半径相等。
输出描述:
最少操作次数。
测试样例:
6
3 2 1 4 6 5
输出:3
问题分析:
本题可转换为思考求数组中递增为1的子序列的最大长度(不必连续)。如样例中最长的递增为1的子序列为[3 4 5]。则最少搬运次数为数组总长度减去最大子序列长度。
题解:
思路一:双循环暴力求解最长的递增为1的子序列。(会超出时间限制)
n = int(input())
nums = input()
nums = [int(i) for i in nums.split()]
max_len = 1
for i in range(len(nums)):
length, num = 1, nums[i]
for j in range(i + 1, len(nums)):
if (nums[j] == num + 1):
num = nums[j]
length += 1
if (length > max_len):
max_len = length
print(len(nums) - max_len)
思路二:优化时间复杂度,使用动态规划进行优化。对每个数记录满足条件的前面已满足条件的个数。
状态方程:dp[i] = dp[nums[i] - 1] + 1。如果dp[nums[i] - 1]存在。
n = int(input())
nums = input()
nums = [int(i) for i in nums.split()]
max_len = 1
map_num = {}
for i in range(len(nums)):
map_num[nums[i]] = 1
if (nums[i] - 1 in map_num):
map_num[nums[i]] = map_num[nums[i] - 1] + 1
if (map_num[nums[i]] > max_len):
max_len = map_num[nums[i]]
print(len(nums) - max_len)