搬石头排序的最少次数

题目描述:
沙滩摆放着一排大小不一的球形石头,已知第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)

你可能感兴趣的:(动态规划,算法,笔试)