Leetcode演算法Java全解答--18. 四數之和
阿新 • • 發佈:2019-01-03
Leetcode演算法Java全解答–18. 四數之和
題目
給定一個包含 n 個整數的陣列 nums 和一個目標值 target,判斷 nums 中是否存在四個元素 a,b,c 和 d ,使得 a + b + c + d 的值與 target 相等?找出所有滿足條件且不重複的四元組。
注意:
答案中不可以包含重複的四元組。
示例:
給定陣列 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
滿足要求的四元組集合為:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]
想法
- 暴力破解:四層迴圈 一把梭
- 套用三層迴圈的思維
原來三數之和 迴圈一次加滑動列表 改成 迴圈兩次加滑動列表
複雜度:n3/n
結果
超過91%的測試案例
時間複雜度/空間複雜度:n3/n
總結
之前卡在這題沒有去做,就是自己沒有想著動手寫
程式碼
我的答案
/************************************** * 題目 給定一個包含 n 個整數的陣列 nums 和一個目標值 target,判斷 nums 中是否存在四個元素 a,b,c 和 d ,使得 a + b + c + d 的值與 target 相等?找出所有滿足條件且不重複的四元組。 注意: 答案中不可以包含重複的四元組。 示例: 給定陣列 nums = [1, 0, -1, 0, -2, 2],和 target = 0。 滿足要求的四元組集合為: [ [-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2] ] **************************************/ /************************************** * * 想法: * 1. 暴力破解:四層迴圈 一把梭 * 2. 套用三層迴圈的思維 * 原來 迴圈一次加滑動列表 改成 迴圈兩次加滑動列表 * 詳細可以看這個: * 複雜度:n3/n * * 我的做法 * 超過91%的測試案例 * 時間複雜度/空間複雜度:n3/n * 程式碼執行過程: * * 總結: * 1. 之前卡在這題沒有去做,就是自己沒有想著動手寫 * ***********************************/ public List<List<Integer>> fourSum(int[] nums, int target) { if (nums == null || nums.length < 4) { return Collections.EMPTY_LIST; } Arrays.sort(nums); List<List<Integer>> result = new ArrayList<>(); for (int i = 0; i < nums.length - 3; i++) { // 如果和之前那個資料相同,則會是重複事件 if (i > 0 && nums[i] == nums[i - 1]) { continue; } int valI = nums[i]; for (int j = i + 1; j < nums.length - 2; j++) { // 如果和之前那個資料相同,則會是重複事件 if (j - i > 1 && nums[j] == nums[j - 1]) { continue; } int valJ = nums[j]; int leftIndex = j + 1; int rightIndex = nums.length - 1; while (leftIndex < rightIndex) { int tmpVal = nums[leftIndex] + nums[rightIndex] + valI + valJ; if (tmpVal > target) { rightIndex--; } else if (tmpVal < target) { leftIndex++; } else { List<Integer> list = new ArrayList<>(); list.add(nums[i]); list.add(nums[j]); list.add(nums[leftIndex]); list.add(nums[rightIndex]); result.add(list); // 用nums[leftIndex] == nums[leftIndex + 1]控制重複 while (leftIndex < rightIndex && nums[leftIndex] == nums[leftIndex + 1]) { leftIndex++; } while (leftIndex < rightIndex && nums[rightIndex] == nums[rightIndex - 1]) { rightIndex--; } leftIndex++; rightIndex--; } } } } return result; }
大佬們的答案
/************************************** * 比我好的答案 better * ***********************************/ public List<List<Integer>> better(int[] nums, int target) { List<List<Integer>> result = new ArrayList<>(); int len = nums.length; if (nums == null || len < 4) { return result; } //排序 Arrays.sort(nums); //確定兩個值兩層迴圈然後確定左右指標 //外迴圈 for (int i = 0; i < len - 3; i++) { //判斷相等 if (i != 0 && nums[i] == nums[i - 1]) { continue; } //最小值大於目標值結束 if (nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) { break; } //最大值小於目標值跳過此迴圈 if (nums[i] + nums[len - 1] + nums[len - 2] + nums[len - 3] < target) { continue; } //內迴圈 for (int j = i + 1; j < len - 2; j++) { //判斷相等 if (j > i + 1 && nums[j] == nums[j - 1]) { continue; } //最小值大於目標值結束 if (nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) { break; } //最大值小於目標值跳過此迴圈 if (nums[i] + nums[j] + nums[len - 2] + nums[len - 1] < target) { continue; } //左右指標尋找滿足條件的值 int left = j + 1; int right = len - 1; while (left < right) { int sum = nums[left] + nums[right] + nums[i] + nums[j]; if (sum == target) { result.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right])); left++; right--; while (left < right && nums[left] == nums[left - 1]) { left++; } while (left < right && nums[right] == nums[right + 1]) { right--; } } else if (sum < target) { left++; } else { right--; } } } } return result; }
測試用例
@Test
public void test018() {
// 建立測試案例
// int[] arr1 = new int[] { 1, 0, -1, 0, -2, 2 };
int[] arr1 = new int[] { 0, 0, 0, 0 };
int target1 = 0;
// 測試案例期望值
List<List<Integer>> expResult1 = new ArrayList<>();
List<Integer> list1 = new ArrayList<>();
list1.add(-1);
list1.add(0);
list1.add(0);
list1.add(1);
List<Integer> list2 = new ArrayList<>();
list2.add(-2);
list2.add(-1);
list2.add(1);
list2.add(2);
List<Integer> list3 = new ArrayList<>();
list2.add(-2);
list2.add(0);
list2.add(0);
list2.add(2);
expResult1.add(list1);
expResult1.add(list2);
expResult1.add(list3);
// 執行方法
Solution018 solution018 = new Solution018();
List<List<Integer>> result1 = solution018.fourSum(arr1, target1);
// 判斷期望值與實際值
Assert.assertEquals(expResult1, result1);
}
其他
“大佬們的答案” 標籤來自leetcode,侵權請聯絡我進行刪改
如有疑問請聯絡,聯絡方式:QQ3060507060