Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonで最大k回の符号反転操作を行い配列の合計を最大化する方法

リスト nums と整数 k が与えられたとします。ここで考える操作とは、nums から要素を1つ選び、その符号を反転させるものです。この操作をちょうど k 回実行したとき、得られる合計値の最大値を求めます。

例えば、入力が nums = [2, 1, -6, -2]、k = 3 の場合、出力は 9 になります。-6、-2、そして 1 の符号を反転すると [2, -1, 6, 2] となり、その合計は 9 になるためです。

解法のアプローチ

この問題は「貪欲法」を使って効率的に解くことができます。手順は以下の通りです。

  • n を nums のサイズとします。
  • n が 0 の場合は 0 を返します。
  • リスト nums を昇順にソートします。
  • idx を 0 から n - 1 までループします。
    • nums[idx] が負の値で、かつ k が 0 より大きい場合:
      • k を 1 減らします。
      • nums[idx] の符号を反転します。
  • k が奇数の場合:(nums の全要素の合計) − (2 × nums の最小値) を返します。
  • それ以外の場合は、nums の全要素の合計を返します。

アルゴリズムのポイント

  • まずソートを行うことで、最も小さい(負の)要素から優先的に符号を反転できます。負の数を正に変えると合計が増えるため、これは常に有利です。
  • すべての負の数を反転しても操作回数が残っている場合、残りが偶数回であれば、同じ要素を2回反転して元に戻せるため合計は変わりません。
  • 残りが奇数回の場合は、どこか1つの要素を余分に反転する必要があります。影響を最小限に抑えるには最小値を選ぶのが最適で、最小値 x を反転すると合計は sum − 2x だけ減少するため、「合計 − 2 × 最小値」を返せばよいのです。

実装例

理解を深めるために、以下のPythonコードを見てみましょう。

def solve(nums, k):
    n = len(nums)
    if n == 0:
        return 0

    nums.sort()
    for idx in range(n):
        if nums[idx] < 0 and k > 0:
            k -= 1
            nums[idx] *= -1

    if k & 1 == 1:
        return sum(nums) - 2 * min(nums)

    return sum(nums)

nums = [2, 1, -6, -2]
k = 3
print(solve(nums, k))

入力

[2, 1, -6, -2], 3

出力

9

  1. Pythonで連続する部分配列の最大積を求めるプログラム

    nums という配列が与えられたとき、少なくとも1つの要素を含む「連続した部分配列」の中から、要素の積が最大になるものを見つけて、その積を返すことを考えます。例えば、配列が [1,9,2,0,2,5] の場合、連続する部分配列 [1,9,2] の積が最大となるため、出力は 18 になります。 解法のアプローチ この問題は動的計画法(DP)を使って効率的に解くことができます。ポイントは、負の数同士を掛けると正の数になる可能性があるため、各位置における「最大積」と「最小積」の両方を追跡することです。 具体的な手順は以下の通りです。 max_list:nums と同じサイズのリストを作成し、0で初

  2. PythonでN=(P!/Q!)を1に減らす最大操作回数を求める方法

    問題の概要 2つの整数 P と Q が与えられ、これらから N = P!/Q! という数が作られます。この N を、実行可能な限り多くの操作回数で 1 まで減らすことを考えます。ここでいう1回の操作とは、「N がある整数 X で割り切れるとき、N を N/X に置き換える」というものです。目的は、この操作を行える最大回数を求めることです。 具体例 入力が A = 7、B = 4 の場合を考えてみましょう。このとき N = 7!/4! = 5 × 6 × 7 = 210 となります。 210 を 1 にするには、素因数ごとに順番に割っていくのが最適です。210 = 2 × 3 × 5 × 7