【LeetCode】396. Rotate Function(java实现)

原题链接

https://leetcode.com/problems/rotate-function/

原题

Given an array of integers A and let n to be its length.
Assume Bk to be an array obtained by rotating the array A k positions clock-wise, we define a “rotation function” F on A as follow:
F(k) = 0 * Bk[0] + 1 * Bk[1] + … + (n-1) * Bk[n-1].
Calculate the maximum value of F(0), F(1), …, F(n-1).

Note:
n is guaranteed to be less than 105.

Example:

A = [4, 3, 2, 6]

F(0) = (0 * 4) + (1 * 3) + (2 * 2) + (3 * 6) = 0 + 3 + 4 + 18 = 25
F(1) = (0 * 6) + (1 * 4) + (2 * 3) + (3 * 2) = 0 + 4 + 6 + 6 = 16
F(2) = (0 * 2) + (1 * 6) + (2 * 4) + (3 * 3) = 0 + 6 + 8 + 9 = 23
F(3) = (0 * 3) + (1 * 2) + (2 * 6) + (3 * 4) = 0 + 2 + 12 + 12 = 26

So the maximum value of F(0), F(1), F(2), F(3) is F(3) = 26.

题目要求

题目叫“旋转函数”(不知道这个翻译是否合适),给定一个数组(数组长度为n),按照F(k)函数的格式求值,然后再将数组位置都向前旋转进一位,比如索引为0的值放到索引为1的位置,1到2,2到3,而n-1则因为越界,排到第0的位置。这样的旋转进行n次,每次都算出F(k)的值,然后求出最大值。
编写测试用例时,需要注意数组为空、数组元素为负时等一些情况。

解法

解法一:直接按照给定的公式,分别计算每个F(k)的值。这种算法的时间复杂度是O(n平方),当n较大时,会超时

public int maxRotateFunction(int[] A) {
    if (A.length == 0) {
        return 0;
    }
    int max = Integer.MIN_VALUE;

    for (int i = 0, k = 0; i < A.length; i++, k++) {
        int temp = 0;
        for (int j = 0; j < A.length; j++) {
            temp += j * A[(j - k + A.length) % A.length];
        }
        max = (max < temp) ? temp : max;
    }

    return max;
}

解法二:动态规划法。为了降低时间复杂度,我们需要想点其他的方法,对比给出的示例,F(0)与F(1)的区别,就是F(0)中除了A[n-1]之外,其他的数字都增加了一倍,并且还要再减去(n-1)*A[n-1],F[0]就是增加了4,3,2,然后再减去了3*6,F[1] = F[0] + 4 + 3 + 2 - 3 * 6 = 16。因此我们可以求出这样一个公式:
F[n] = F[n - 1] + (sum - A[sumIndex]) - (A.length - 1) * A[sumIndex]
其中,sumIndex = -n + A.length,即旋转时要从索引n-1移动到0的那个值。sum为数组A中所有值的和,而(sum - A[sumIndex]) 自然就是数组A中除了索引为sumIndex之外其他所有值的和。
这种解法的时间复杂度是O(n)。

public int maxRotateFunction(int[] A) {
    int sum = 0;
    // 计算出sum
    for (int i = 0; i < A.length; i++) {
        sum += A[i];
    }

    int base = 0;
    // 计算出F[0]的值
    for (int i = 0; i < A.length; i++) {
        base += i * A[i];
    }

    int max = base;
    for (int i = 1; i < A.length; i++) {
        int sumIndex = -i + A.length;
        // 公式展开后,得出如下
        base += sum - A.length * A[sumIndex];   // base += (sum - A[sumIndex]) - (A.length - 1) * A[sumIndex]; 
        max = (max < base) ? base : max;
    }
    return max;
}

测试用例:

public static void main(String[] args) {
    Solution s = new Solution();
    {
        int []A = new int[]{};
        assert(s.maxRotateFunction(A) == 0);
    }
    {
        int []A = new int[]{4, 3, 2, 6};
        assert(s.maxRotateFunction(A) == 26);
    }
    {
        int []A = new int[]{-1};
        assert(s.maxRotateFunction(A) == 0);
    }
    {
        int size = 65535;
        int []A = new int[size];
        for (int i = 0; i < size; i++) {
            A[i] = i - 3;
        }
        assert(s.maxRotateFunction(A) == 2147408563);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值