0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

day7 at Leetcode

0
Last updated at Posted at 2026-07-13

238. Product of Array Except Self

最初こう考えたが、remove() は値を消す関数であって、インデックスを消す関数ではなかった。

class Solution:
    def productExceptSelf(self, nums: List[int]) -> List[int]:
        for i in range(len(nums)):
            numss = nums.remove(i)
            result = 1
            for n in numss:
                result *= n
        return result

remove(i) は「値が i の要素」を消してしまう上に、戻り値が None なので for n in numss がそもそもエラーになる。

次に、元のリストをコピーしてから使えばいいのではと考えたが、tmp = nums はコピーではなく同じリストを指すだけという罠にハマった。

class Solution:
    def productExceptSelf(self, nums: List[int]) -> List[int]:
        tmp = nums
        resultlist=[]
        for i in range(len(nums)):
            nums=tmp
            nums.remove(nums[i])
            result = 1
            for n in nums:
                result *= n
        resultlist.append(result)
        return resultlist

tmp = nums はエイリアス(別名)を作るだけなので、nums.remove() すると tmp の中身も一緒に減っていく。ループのたびにリストがどんどん縮んでいき、最終的に IndexError になった。しかも resultlist.append(result) がループの外にあったので、仮に動いても最後の1個しか結果が入らなかった。

修正版:

class Solution:
    def productExceptSelf(self, nums: List[int]) -> List[int]:
        resultlist = []
        for i in range(len(nums)):
            excluded = nums[:i] + nums[i+1:]   # コピーではなく「除いた新しいリスト」を毎回作る
            result = 1
            for n in excluded:
                result *= n
            resultlist.append(result)          # ループの中でappend
        return resultlist

nums[:i] + nums[i+1:] で「i番目を除いた新しいリスト」を毎回スライスで作ることで、元の nums を一切破壊せずに済んだ。値の重複があっても安全。

ただし内側の for n in excluded も外側の for i も両方 O(n) なので、全体では O(n²)。この問題は本来 O(n)・割り算なしが条件なので、次は「左からの累積積」「右からの累積積」を別々に持っておく方式に挑戦した。

O(n)への改善
O(n²) 版は各 i ごとにリストを作り直して for で全部掛け直していた(ループの中にループ)ので遅い。「左からの累積積」と「右からの累積積」を別々に持っておいて最後に掛け合わせれば、ループを2回(+掛け合わせで1回)に減らせる。

インデックス: 0 1 2 3
nums: 1 2 3 4
左からの積(prefix): 1 1 2 6 ← nums[i]より左の積(自分は含まない)
右からの積(suffix): 24 12 4 1 ← nums[i]より右の積(自分は含まない)
answer[i] = prefix[i] * suffix[i]
answer: 24 12 8 6

class Solution:
    def productExceptSelf(self, nums: List[int]) -> List[int]:
        n = len(nums)
        prefix = [1] * n
        suffix = [1] * n

        # 左からの累積積を作る
        for i in range(1, n):
            prefix[i] = prefix[i-1] * nums[i-1]

        # 右からの累積積を作る
        for i in range(n-2, -1, -1):
            suffix[i] = suffix[i+1] * nums[i+1]

        # 掛け合わせる
        return [prefix[i] * suffix[i] for i in range(n)]

前の O(n²) 版は「1個ずつリストを作って全部掛け直す」を n 回繰り返していたのに対して、今回は「左から1周」「右から1周」「掛け合わせで1周」の合計3周(=O(n))で終わるのがポイント。割り算も使っていない。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?