文章
この種のトピックには複雑なアルゴリズム論理はなく、動的計画法は使用されません。テストされるのは思考能力です。理解できれば、それを書くことができます。もちろん、コードの最終的な実装では、考慮する必要のある多くの状況があり、ロジックは厳密です。
トピック1:3つの数値の合計
[LeetCode-15から](中程度)
n個の整数を含む配列numsが与えられた場合、a + b + c = 0となるようなnumsに3つの要素a、b、cがあるかどうかを判断しますか?合計が0で、繰り返されないすべてのトリプルを見つけてください。注:回答に重複するトリプルを含めることはできません。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:
输入:nums = []
输出:[]
示例 3:
输入:nums = [0]
输出:[]
私の思考の列:
私の先生はかつて、「2つのforループが解決できないという問題はありません。もしあれば、もう1つ追加してください」と言いました。編集者は、ブルートフォースソリューションとバブルソートの概念を採用しています。他の人の計画を見てみると、自分が書いたものの方がわかりやすく、時間もメモリ消費量も中〜高レベルで悪くないことがわかりました。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
// 先排序,方便计算
Arrays.sort(nums);
// 把题干中的0当成变量设置,让代码更灵活
int sum = 0;
for (int i = 0;i < nums.length;i++) {
// 排序之后如果第一个元素已经大于 sum,那么无论如何组合都不可能凑成三元组
// 直接返回结果就可以了
if (nums[i] > sum) break;
// 错误去重方法,将会漏掉-1,-1,2 这种情况
// if (nums[i] == nums[i + 1]) continue;
if (i > 0 && nums[i] == nums[i - 1]) continue;
int left = i + 1, right = nums.length - 1;
while (right > left) {
int temp = nums[i] + nums[left] + nums[right];
if (temp == sum) {
result.add(Arrays.asList(nums[i], nums[left], nums[right]));
// 去重用的
while (right > left && nums[left] == nums[left+1]) left++;
while (right > left && nums[right] == nums[right-1]) right--;
// 找到答案时,双指针同时收缩
left++;
right--;
} else if (temp > sum) {
right--;
} else {
left++;
}
}
}
return result;
}
}
トピック2:最も近い3つの数値の合計
[LeetCode-16から](中程度)
長さnの整数配列numsとターゲット値targetが与えられます。合計がターゲットに最も近いnumsから3つの整数を選択してください。これらの3つの数値の合計を返します。注:入力のセットごとに1つのソリューションが存在すると想定されています。
示例 1:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
示例 2:
输入:nums = [0,0,0], target = 1
输出:0
提示:
3 <= nums.length <= 1000
-1000 <= nums[i] <= 1000
-104 <= target <= 104
私の思考の列:
これはLeetCode-15の質問のバリエーションです。考え方は同じですが、質問は必ずしも目標値と同じではありません。最も近いアイデアは、絶対値Math.abs()を使用して最も近い結果を保証することです。
class Solution {
public int threeSumClosest(int[] nums, int target) {
// 先排序
Arrays.sort(nums);
int min = nums[0] + nums[1] + nums[2];
for (int i = 0;i < nums.length;i++) {
// 设置左右指针
int left = i+1, right = nums.length-1;
while (right > left) {
int threeSum = nums[i] + nums[left] + nums[right];
// 计算最小绝对值的min
if (Math.abs(threeSum - target) < Math.abs(min - target)) {
min = threeSum;
}
if (threeSum > target) {
right--;
} else if (threeSum < target) {
left++;
} else {
// 如果已经等于 target 的话, 肯定是最接近的
return threeSum;
}
}
}
// 通知GC,本行代码影响不大
System.gc();
return min;
}
}