這個問題在線性時間和空間中看起來很容易解決。這個問題建立在數組的一些基本概念之上。
- 數組遍歷。
- 前綴和後綴之和。
在程式設計面試中提出這個問題的公司有 Facebook、亞馬遜、蘋果、Netflix、Google、微軟、Adobe 以及許多其他頂尖科技公司。
問題陳述
給定一個整數數組 nums,傳回一個數組 answer,使得 answer[i] 等於 nums 中除 nums[i] 之外的所有元素的乘積。
nums 的任何前綴或後綴的乘積保證適合32位元整數。
您必須編寫一個在 O(n) 時間內運作且不使用除法運算的演算法。
測試案例#1:
Input: nums = [1,2,3,4] Output: [24,12,8,6]
測試案例#2:
Input: nums = [-1,1,0,-3,3] Output: [0,0,9,0,0]
了解問題
這個問題在線性時間和空間上看起來更容易解決,但在編寫偽代碼或實際程式碼實作時卻很棘手。
插圖
讓我們來看看包含 4 個元素的簡單陣列的預期結果:
input = {1, 2, 3, 4}
因此,每個索引處的值是數組中除該值本身之外的所有其他元素的乘積。下圖說明了這一點。
根據上圖,我們可以得到一個公式。對於任何給定的索引 i,我們可以使用從 o 到 (i - 1) 的元素的乘積加上從 (i 1) 到 (N - 1) 的元素的乘積來找到該值。如下圖:
思維過程
在寫偽代碼之前,先提出問題並向面試官提問。
- 我該擔心重複嗎?
- 如果陣列為空或只有一個元素怎麼辦?預期結果是什麼?
- 我應該考慮/忽略數組中任何索引中的 0 值嗎?因為除了包含 0 的索引之外,所有其他值都為 0。
- 這個問題的極端/邊緣情況是什麼?
一旦你和麵試官討論了上述問題,就想出各種方法來解決問題。
- 天真的方法/暴力。
- 所有元素的乘積。
- 左右產品。
- 前綴和後綴總和。
方法 1:樸素/暴力
直覺
要採用強力方法,我們必須執行兩個 for 迴圈。當外循環索引與內循環索引值相符時,我們應該跳過乘積;否則,我們將繼續使用該產品。
演算法
- 初始化變數:
- N = nums.length(輸入陣列的長度)。
- result = new int[N] (儲存結果的陣列)。
- 外循環(迭代 nums 中的每個元素):
- 對於 i = 0 到 N-1:初始化 currentProduct = 1。
- 內循環(計算當前元素的乘積),對於 j = 0 到 N-1:
- 如果 i == j,則使用 continue 跳過目前迭代。
- 將 currentProduct 乘以 nums[j]。
- 將 currentProduct 分配給 result[i]。
- 傳回結果。
程式碼
// brute force static int[] bruteForce(int[] nums) { int N = nums.length; int[] result = new int[N]; for (int i = 0; i <h3> 複雜度分析 </h3> <ol> <li> <strong>時間複雜度</strong>:O(n^2),用於在外循環和內循環中迭代數組兩次。 </li> <li> <strong>空間複雜度</strong>:O(n),對於我們使用的輔助空間(result[]陣列)。 </li> </ol> <h2> 方法 2:陣列 ❌ 的乘積 </h2> <p>大多數開發人員認為的一種方法是運行所有元素的乘積和,將乘積和除以每個數組值,然後返回結果。 </p> <h3> 虛擬程式碼 </h3> <pre class="brush:php;toolbar:false">// O(n) time and O(1) space p = 1 for i -> 0 to A[i] p * = A[i] for i -> 0 to (N - 1) A[i] = p/A[i] // if A[i] == 0 ? BAM error‼️
程式碼
// code implementation static int[] productSum(int[] nums) { int product_sum = 1; for(int num: nums) { product_sum *= num; } for(int i = 0; i <p>如果陣列元素之一包含 0 怎麼辦? ? </p> <p>除了包含0的索引之外,所有索引的值肯定是無限大。另外,程式碼會拋出 java.lang.ArithmeticException。 <br> </p> <pre class="brush:php;toolbar:false">Exception in thread "main" java.lang.ArithmeticException: / by zero at dev.ggorantala.ds.arrays.ProductOfArrayItself.productSum(ProductOfArrayItself.java:24) at dev.ggorantala.ds.arrays.ProductOfArrayItself.main(ProductOfArrayItself.java:14)
方法 3:找出前綴和後綴乘積
在我的網站上的數組掌握課程中了解有關前綴和後綴和的更多信息 https://ggorantala.dev
直覺與公式
前綴和後綴是在為結果編寫演算法之前計算的。字首和字尾總和公式如下:
Algorithm Steps
- Create an array result of the same length as nums to store the final results.
- Create two additional arrays prefix_sum and suffix_sum of the same length as nums.
- Calculate Prefix Products:
- Set the first element of prefix_sum to the first element of nums.
- Iterate through the input array nums starting from the second element (index 1). For each index i, set prefix_sum[i] to the product of prefix_sum[i-1] and nums[i].
- Calculate Suffix Products:
- Set the last element of suffix_sum to the last element of nums.
- Iterate through the input array nums starting from the second-to-last element (index nums.length - 2) to the first element. For each index i, set suffix_sum[i] to the product of suffix_sum[i+1] and nums[i].
- Calculate the result: Iterate through the input array nums.
- For the first element (i == 0), set result[i] to suffix_sum[i + 1].
- For the last element (i == nums.length - 1), set result[i] to prefix_sum[i - 1].
- For all other elements, set result[i] to the product of prefix_sum[i - 1] and suffix_sum[i + 1].
- Return the result array containing the product of all elements except the current element for each index.
Pseudocode
Function usingPrefixSuffix(nums): N = length of nums result = new array of length N prefix_sum = new array of length N suffix_sum = new array of length N // Calculate prefix products prefix_sum[0] = nums[0] For i from 1 to N-1: prefix_sum[i] = prefix_sum[i-1] * nums[i] // Calculate suffix products suffix_sum[N-1] = nums[N-1] For i from N-2 to 0: suffix_sum[i] = suffix_sum[i+1] * nums[i] // Calculate result array For i from 0 to N-1: If i == 0: result[i] = suffix_sum[i+1] Else If i == N-1: result[i] = prefix_sum[i-1] Else: result[i] = prefix_sum[i-1] * suffix_sum[i+1] Return result
Code
// using prefix and suffix arrays private static int[] usingPrefixSuffix(int[] nums) { int[] result = new int[nums.length]; int[] prefix_sum = new int[nums.length]; int[] suffix_sum = new int[nums.length]; // prefix sum calculation prefix_sum[0] = nums[0]; for (int i = 1; i = 0; i--) { suffix_sum[i] = suffix_sum[i + 1] * nums[i]; } for (int i = 0; i <h3> Complexity analysis </h3> <ol> <li> <strong>Time complexity</strong>: The time complexity of the given code is O(n), where n is the length of the input array nums. This is because: <ul> <li>Calculating the prefix_sum products take O(n) time.</li> <li>Calculating the suffix_sum products take O(n) time.</li> <li>Constructing the result array takes O(n) time.</li> </ul> </li> </ol> <p>Each of these steps involves a single pass through the array, resulting in a total time complexity of O(n)+O(n)+O(n) = 3O(n), which is O(n).</p> <ol> <li> <strong>Space complexity</strong>: The space complexity of the given code is O(n). This is because: <ul> <li>The prefix_sum array requires O(n) space.</li> <li>The suffix_sum array requires O(n) space.</li> <li>Theresult array requires O(n) space. All three arrays are of length n, so the total space complexity is O(n) + O(n) + O(n) = 3O(n), which is O(n).</li> </ul> </li> </ol> <h3> Optimization ? </h3> <p>For the suffix array calculation, we override the input nums array instead of creating one.<br> </p> <pre class="brush:php;toolbar:false">private static int[] usingPrefixSuffixOptimization(int[] nums) { int[] result = new int[nums.length]; int[] prefix_sum = new int[nums.length]; // prefix sum calculation prefix_sum[0] = nums[0]; for (int i = 1; i = 0; i--) { nums[i] = nums[i + 1] * nums[i]; } for (int i = 0; i <p>Hence, we reduced the space of O(n). Time and space are not reduced, but we did a small optimization here.</p> <h2> Approach 4: Using Prefix and Suffix product knowledge ? </h2> <h3> Intuition </h3> <p>This is a rather easy approach when we use the knowledge of prefix and suffix arrays.</p> <p>For every given index i, we will calculate the product of all the numbers to the left and then multiply it by the product of all the numbers to the right. This will give us the product of all the numbers except the one at the given index i. Let's look at a formal algorithm that describes this idea more clearly.</p> <h3> Algorithm steps </h3> <ol> <li>Create an array result of the same length as nums to store the final results.</li> <li>Create two additional arrays prefix_sum and suffix_sum of the same length as nums.</li> <li>Calculate Prefix Products: <ul> <li>Set the first element of prefix_sum to 1.</li> <li>Iterate through the input array nums starting from the second element (index 1). For each index i, set prefix_sum[i] to the product of prefix_sum[i - 1] and nums[i - 1].</li> </ul> </li> <li>Calculate Suffix Products: <ul> <li>Set the last element of suffix_sum to 1.</li> <li>Iterate through the input array nums starting from the second-to-last element (index nums.length - 2) to the first element.</li> <li>For each index i, set suffix_sum[i] to the product of suffix_sum[i + 1] and nums[i + 1].</li> </ul> </li> <li>Iterate through the input array nums. <ul> <li>For each index i, set result[i] to the product of prefix_sum[i] and suffix_sum[i].</li> </ul> </li> <li>Return the result array containing the product of all elements except the current element for each index.</li> </ol> <h3> Pseudocode </h3> <pre class="brush:php;toolbar:false">Function prefixSuffix1(nums): N = length of nums result = new array of length N prefix_sum = new array of length N suffix_sum = new array of length N // Calculate prefix products prefix_sum[0] = 1 For i from 1 to N-1: prefix_sum[i] = prefix_sum[i-1] * nums[i-1] // Calculate suffix products suffix_sum[N-1] = 1 For i from N-2 to 0: suffix_sum[i] = suffix_sum[i+1] * nums[i+1] // Calculate result array For i from 0 to N-1: result[i] = prefix_sum[i] * suffix_sum[i] Return result
Code
private static int[] prefixSuffixProducts(int[] nums) { int[] result = new int[nums.length]; int[] prefix_sum = new int[nums.length]; int[] suffix_sum = new int[nums.length]; prefix_sum[0] = 1; for (int i = 1; i = 0; i--) { suffix_sum[i] = suffix_sum[i + 1] * nums[i + 1]; } for (int i = 0; i <h3> Complexity analysis </h3> <ol> <li> <strong>Time complexity</strong>: The time complexity of the given code is O(n), where n is the length of the input array nums. This is because: <ul> <li>Calculating the prefix_sum products take O(n) time.</li> <li>Calculating the suffix_sum products take O(n) time.</li> <li>Constructing the result array takes O(n) time.</li> </ul> </li> </ol> <p>Each of these steps involves a single pass through the array, resulting in a total time complexity of O(n)+O(n)+O(n) = 3O(n), which is O(n).</p> <ol> <li> <strong>Space complexity</strong>: The space complexity of the given code is O(n). This is because: <ul> <li>The prefix_sum array requires O(n) space.</li> <li>The suffix_sum array requires O(n) space.</li> <li>The result array requires O(n) space.</li> </ul> </li> </ol> <p>All three arrays are of length n, so the total space complexity is O(n) + O(n) + O(n) = 3O(n), which is O(n).</p> <h2> Approach 5: Carry Forward technique </h2> <h3> Intuition </h3> <p>The carry forward technique optimizes us to solve the problem with a more efficient space complexity. Instead of using two separate arrays for prefix and suffix products, we can use the result array itself to store intermediate results and use a single pass for each direction.</p> <p>Here’s how you can implement the solution using the carry-forward technique:</p> <h3> Algorithm Steps for Carry Forward Technique </h3> <ol> <li>Initialize Result Array: <ul> <li>Create an array result of the same length as nums to store the final results.</li> </ul> </li> <li>Calculate Prefix Products: <ul> <li>Initialize a variable prefixProduct to 1.</li> <li>Iterate through the input array nums from left to right. For each index i, set result[i] to the value of prefixProduct. Update prefixProduct by multiplying it with nums[i].</li> </ul> </li> <li>Calculate Suffix Products and Final Result: <ul> <li>Initialize a variable suffixProduct to 1.</li> <li>Iterate through the input array nums from right to left. For each index i, update result[i] by multiplying it with suffixProduct. Update suffixProduct by multiplying it with nums[i].</li> </ul> </li> <li>Return the result array containing the product of all elements except the current element for each index.</li> </ol> <h3> Pseudocode </h3> <pre class="brush:php;toolbar:false">prefix products prefixProduct = 1 For i from 0 to N-1: result[i] = prefixProduct prefixProduct = prefixProduct * nums[i] // Calculate suffix products and finalize result suffixProduct = 1 For i from N-1 to 0: result[i] = result[i] * suffixProduct suffixProduct = suffixProduct * nums[i] Return result
Code
// carry forward technique private static int[] carryForward(int[] nums) { int n = nums.length; int[] result = new int[n]; // Calculate prefix products int prefixProduct = 1; for (int i = 0; i = 0; i--) { result[i] *= suffixProduct; suffixProduct *= nums[i]; } return result; }
Explanation
- Prefix Products Calculation:
- We initialize prefixProduct to 1 and update each element of result with the current value of prefixProduct.
- Update prefixProduct by multiplying it with nums[i].
- Suffix Products Calculation:
- We initialize suffixProduct to 1 and update each element of result(which already contains the prefix product) by multiplying it with suffixProduct.
- Update suffixProduct by multiplying it with nums[i].
Complexity analysis
- Time Complexity: O(n) time
- Space Complexity: O(n) (for the result array)
This approach uses only a single extra array (result) and two variables (prefixProduct and suffixProduct), achieving efficient space utilization while maintaining O(n) time complexity.
以上是Leetcode:除自身之外的陣列的乘積的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本文討論了使用Maven和Gradle進行Java項目管理,構建自動化和依賴性解決方案,以比較其方法和優化策略。

本文使用Maven和Gradle之類的工具討論了具有適當的版本控制和依賴關係管理的自定義Java庫(JAR文件)的創建和使用。

本文討論了使用咖啡因和Guava緩存在Java中實施多層緩存以提高應用程序性能。它涵蓋設置,集成和績效優勢,以及配置和驅逐政策管理最佳PRA

本文討論了使用JPA進行對象相關映射,並具有高級功能,例如緩存和懶惰加載。它涵蓋了設置,實體映射和優化性能的最佳實踐,同時突出潛在的陷阱。[159個字符]

Java的類上載涉及使用帶有引導,擴展程序和應用程序類負載器的分層系統加載,鏈接和初始化類。父代授權模型確保首先加載核心類別,從而影響自定義類LOA

本文解釋了用於構建分佈式應用程序的Java的遠程方法調用(RMI)。 它詳細介紹了接口定義,實現,註冊表設置和客戶端調用,以解決網絡問題和安全性等挑戰。

本文詳細介紹了用於網絡通信的Java的套接字API,涵蓋了客戶服務器設置,數據處理和關鍵考慮因素,例如資源管理,錯誤處理和安全性。 它還探索了性能優化技術,我

本文詳細介紹了創建自定義Java網絡協議。 它涵蓋協議定義(數據結構,框架,錯誤處理,版本控制),實現(使用插座),數據序列化和最佳實踐(效率,安全性,維護


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

Atom編輯器mac版下載
最受歡迎的的開源編輯器

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

禪工作室 13.0.1
強大的PHP整合開發環境

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

SublimeText3漢化版
中文版,非常好用