- 两数之和
.给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
最容易想到的思路:暴力双循环
就是把已知数组的任意两个元素求和得到sum与target进行比较…
这种方式的差劲之处在此不表…
class Solution {
public int[] twoSum(int[] nums, int target) {
for (int i = 0; i < nums.length; i++) {//第一层循环从第0个元素开始
for (int j = i + 1; j < nums.length; j++) {//从第i+1元素开始
if (nums[j] + nums[i] == target) {
return new int[] {i,j};
}
}
}
return new int[0];
}
}
比较好的思路哈希表法
通过建立一个哈希表来换取时间复杂度的降低.
具体思路:我开始也不知道什么是哈希表
哈希表就是你建立一个容器,这个容器可以存储两个要素一个key和一个value
对于这个题目来说,key=target-nums[]; value就是这个key是通过数组下标为几的元素减出来的那个下标值.
每得到一个key我们就把它存入哈希表中顺便把value也存进去…然而在每次往哈希表中存东西的时候我们就要检查一遍哈希表中是否已经存入了我们需要的那个数字就可以达成目标的元素…如果没有就继续往下进行,如果有那么非常好
class Solution {
public int[] twoSum(int[] nums, int target) {
//element index
HashMap<Integer,Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int diff = target - nums[i];
if (map.containsKey(diff)) {
return new int[]{map.get(diff), i};
}
else{
map.put(nums[i],i);
}
}
return new int[]{-1,-1};
}
}
[3 ,2 , 11, 7]
//key value
9 - 3 = 6 0 //先在哈希表中找6,没找到,(3,0)存入哈希表,
9 - 2 = 7 1 //先在哈希表中找7,没找到(2,1)存入哈希表,
9 - 11=-2 2 //先在哈希表中找-2,没找到(11,2)存入哈希表,
9 - 7 = 2 3 //先在哈希表中找2,找到了返回2对应的index=1,再返回自己的index=3
- 缺失数字
给定一个包含 0, 1, 2, …, n 中 n 个数的序列,找出 0 … n 中没有出现在序列中的那个数。
示例 1:
输入: [3,0,1] 输出: 2 示例 2:
输入: [9,6,4,2,3,5,7,0,1] 输出: 8
说明: 你的算法应具有线性时间复杂度。你能否仅使用额外常数空间来实现?
其实我的第一个思路是写一个双循环第一层循环为0 ~ n第二层循环为数组的下标然后在第二层循环里面看能否找到对应的那个数字,如过能找到就break内层循环返回上一层循环,在i++,再进入内层循环…直到在内层循环中找不到对应的i那么就返回i;
class Solution {
public int missingNumber(int[] nums) {
for (int i = 0; i <= nums.length; i++) {
for (int j = 0; j < nums.length; j++) {
if (i == nums[j]) {
break;
}
if(j == nums.length-1){
return i;
}
}
}
return -1;
}
}
//执行用时:252 ms, 在所有 Java 提交中击败了10.76%的用户
//内存消耗:39.7 MB, 在所有 Java 提交中击败了18.67%的用户
然后就看题解,看到了这种先排序,然后对这个有序的数组再进行判断只不过这种方法有一个明显的弊端,要单独考虑缺失的数字是0/n的情况…而且合并不进循环中去,数组访问下标越界…
class Solution {
public int missingNumber(int[] nums) {
Arrays.sort(nums);//给数组排序
//如果0没有在第一个位置,则返回0
if(nums[0] != 0){
return 0;
}
//如果n没有在最后一个位置,则返回n
if(nums[nums.length-1] != nums.length){
return nums.length;
}
for (int i = 1; i < nums.length; i++) {
int expectedNum = nums[i-1] + 1;
if(nums[i] != expectedNum){
return expectedNum;
}
}
return -1;
}
}
/*执行用时:7 ms, 在所有 Java 提交中击败了10.76%的用户
内存消耗:39.6 MB, 在所有 Java 提交中击败了32.95%的用户*/
哈希表的方法又来了…
我们先回顾一下哈希表法通过建立一个容器,这个容器里面一次存储的是两个要素即key和value,嗯嗯嗯那么我们想一想这个题存什么东西???NONONO,看来我对哈希表法有什么误解吧!!!
这个题是通过建立一个哈希表把数组的元素都放进去,然后呢直接查询i是否在里面如果在就继续,如果不在了,那就返回i(I的范围是从0~N(N是数组的长度)) 哎哎哎哎哎 ,熟练运用哈希表的方法还任重而道远啊啊啊啊啊啊啊啊!!!
class Solution {
public int missingNumber(int[] nums) {
HashSet<Integer> set = new HashSet<>();
for (int num:nums){
set.add(num);
}
for (int i = 0; i < nums.length; i++) {
if(!set.contains(i)){
return i;
}
}
return nums.length;
}
}
//执行用时:6 ms, 在所有 Java 提交中击败了27.79%的用户
//内存消耗:39.4 MB, 在所有 Java 提交中击败了59.85%的用户
哈哈,这个题有一个数学方法------它这题目的数据很特殊是从0~n一个连续的数组虽然可能中间缺少了一个数字,
但是我们可以通过求0~n的和然后减去这个数组元素的求和那么结果不就出来了吗??
真是一种非常有趣的做法…
//嗯嗯嗯嗯嗯,我想的还是太简单了,,,,,,,虽然在LeetCode上能通过,,,,
//但是有大佬提出了我这种写法比较容易造成溢出,,,,,,那我就再改进一下下
class Solution {
public int missingNumber(int[] nums) {
int sum_n = 0;
int sum_nums = 0;
for (int i = 0; i <= nums.length ; i++) {
sum_n += i;
}
for (int i = 0; i < nums.length; i++) {
sum_nums += nums[i];
}
return (sum_n-sum_nums);
}
}
//执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
//内存消耗:39.2 MB, 在所有 Java 提交中击败了81.96%的用户
//数学方法的改进
class Solution{
public int missingNumber(int[] nums){
int expectedNum = 0;
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum = i - nums[i];
expectedNum += sum;
}
return expectedNum+nums.length;
}
}
//执行用时:1 ms, 在所有 Java 提交中击败了54.05%的用户
//内存消耗:39.4 MB, 在所有 Java 提交中击败了63.11%的用户
//唉唉唉唉,,,,,,,请原谅我,我太菜了,,,,,,,,我也不知道为啥这样效率还变低了........
//执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
//内存消耗:39.3 MB, 在所有 Java 提交中击败了71.04%的用户
//请原谅我,,,,这应该是LeetCode的原因,,,,,,我又重新提交了一遍,,,,发现数据又改变了 .....
78. 子集
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/subsets
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
无思路,先来一个图解吧::::::
直接想吧:::::
/*
* [1, 2, 3]
*
*
* [ ]
* ↓ 1
* [ ] [1]
* ↓ 2
* [ ] [1] [2] [1,2]
* ↓ 3
* [ ] [1] [2] [1,2] [3] [1,3] [2,3] [1,2,3]
*
*
*
*
*
*
*
*
*/
class Solution{
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
res.add(new ArrayList<>());
for (int num:nums){
int resLength = res.size();
for (int i = 0; i < resLength; i++) {
List<Integer> cur = new ArrayList<>(res.get(i));
cur.add(num);
res.add(cur);
}
}
return res;
}
}
思路二:回溯(Backtracking)
/*
* [1, 2, 3]
*
*
* 0 [ ]
* ↓
* 1 [1] [2] [3]
* ↓
* 2 [1,2 ] [1,3] [2,3]
* ↓
* 3 [1,2,3]
*
*
*
*
*
*
*/
思路三:DFS:深度优先
/*
* [1, 2, 3]
*
*
* [ 空集 ]
* ↙ ↓ ↘ ([1,2,3])
* [1] [2] [3]
* ([2,3]) ↙ ↘ ↓
* [1,2 ] [1,3] [2,3]
* ([3]) ↙
* [1,2.3]
*
*
*
*/