给定一个数组和一个目标整数,找出数组中两数之和和整数相等的数

1.算法描述

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

2.要求运行结果eg:

输入:nums = [3,2,4], target = 6
输出:[1,2]

3.java demo实现

1).for循环实现

public int[] twoSum(int[] nums, int target) {
        int[] sumArray=new int[2];
       
        for(int i=0;i<nums.length;i++){
            for(int j=i+1;j<nums.length;j++){
                if(nums[i]+nums[j]==target){
                    sumArray[0]=i;
                    sumArray[1]=j;
                    System.out.print("["+i+","+j+"]");
                    break;
                }
            }
        }
        return sumArray;
    }

2).hashmap实现

public int[] twoSum(int[] nums, int target) {
        int[] sumArray=new int[2];
        HashMap<Integer,Integer> tempNum=new HashMap<>(); 
        tempNum.put(nums[0],0);
        for(int i=0;i<nums.length;i++){
            int matchNum=target-nums[i];
            if(tempNum.containsKey(matchNum)){
                sumArray[0]=i;
                sumArray[1]=tempNum.get(matchNum);
            }else{
                tempNum.put(nums[i],i);
            }
        }
        
        return sumArray;
    }

<think>嗯,用户让我介绍一下子数组之和的问题,也就是LintCode上的138题。题目是给定一个整数数组找出为0的子数组,返回起始结束位置。而且要使用哈希表的方法来实现。我得仔细想想怎么解决这个问题。 首先,我需要理解问题。子数组为0,也就是说,数组中存在某个连续的元素序列,它们的等于0。比如例子中的数组{3,1,2,-3,4},子数组[1,2,-3]的是0,所以起始位置1,结束位置3。或者可能还有其他的子数组,但只需要返回其中一个就行。 那怎么高效地找到这样的子数组呢?暴力解法是枚举所有可能的子数组,计算它们的,这样时间复杂度是O(n²),对于大数组来说效率太低了。题目要使用哈希表,所以应该考虑如何优化。 这时候想到前缀的概念。前缀数组prefix的第i项表示从数组开头到第i个元素。如果两个不同位置的前缀相等,那么这两个位置之间的子数组就是0。比如,假设prefix[j] = prefix[i],那么i+1到j的子数组是0。 那如何利用这个性质呢?可以用一个哈希表来记录每个前缀第一次出现的位置。遍历数组时,计算当前的前缀,如果这个在哈希表中已经存在,说明之前某个位置到当前位置的子数组为0,直接返回那个位置的下一位置到当前位置的索引。如果遇到当前前缀为0的情况,说明从开头到当前位置的是0,直接返回0到当前索引。 举个例子,比如数组nums = [3,1,2,-3,4]。计算前缀数组的话: prefix[0] = 3 prefix[1] = 3+1=4 prefix[2] = 4+2=6 prefix[3] = 6 + (-3) =3 → 这时候发现prefix[3]等于prefix[0],所以子数组是索引0+1=1到3,即子数组[1,2,-3],对应返回[1,3]。 那具体怎么实现呢?步骤如下: 1. 初始化哈希表,用来存储前缀对应的索引。初始时,可以放入一个0的前缀,对应索引-1,这样当某个位置的前缀为0时,可以直接得到从0到当前位置的子数组。 2. 遍历数组,计算当前的前缀。 3. 检查当前前缀是否存在于哈希表中: - 如果存在,取出对应的索引i,那么子数组是i+1到当前索引,返回即可。 - 如果不存在,将当前前缀索引存入哈希表。 4. 由于题目保证存在这样的子数组,所以循环中一定能找到结果。 需要注意边界情况,比如子数组从第一个元素开始的情况。例如数组[-1,1],前缀第一次为-1,第二次为0。这时候哈希表中初始有0:-1,当第二次前缀为0时,得到i=-1,所以子数组从0到1,返回[0,1]。 那代码的大致结构是: 创建一个哈希表,初始放入{0: -1}。 初始化前缀为0。 遍历数组,每次加上当前元素得到新的前缀。 如果这个前缀已经在哈希表中存在,返回哈希表中的+1到当前索引。 否则,将前缀当前索引存入哈希表。 这样时间复杂度是O(n),空间复杂度也是O(n),因为哈希表存储前缀。 测试一下例子是否正确。例如nums = [3,1,2,-3,4]: 遍历过程: i=0,num=3,前缀为3。哈希表中没有3,存入{0:-1,3:0}。 i=1,num=1,前缀4,不存在,存入。 i=2,num=2,前缀6,存入。 i=3,num=-3,前缀3。此时哈希表中有3对应的0。所以返回[0+1,3],即[1,3],正确。 另一个例子,nums = [-1,1],初始哈希表有0:-1。 i=0,前缀-1,不存在,存入。 i=1,前缀0。哈希表存在0,对应的-1,返回[-1+1,1]即[0,1]。 那这样的逻辑应该正确。那接下来按照这个思路写代码的话,需要注意索引的处理。因为题目中的起始结束位置是否是闭区间?比如例子中的答案给出的是(0,2)或者(1,3)。假设这里的结束位置是闭区间,比如在例子中,子数组是索引1到3(包含3),那么对应的起始是1,结束是3。所以在代码中,当找到前缀重复时,返回的是map[sum] +1到当前i。 所以在代码中,当发现当前前缀存在于哈希表,那么返回的起始位置是哈希表里存的索引+1,结束位置是当前的i。 这样应该没问题。那代码的结构大致是: vector<int> subarraySum(vector<int> &nums) { unordered_map<int, int> hash; hash[0] = -1; int sum = 0; for (int i = 0; i < nums.size(); ++i) { sum += nums[i]; if (hash.find(sum) != hash.end()) { return {hash[sum] + 1, i}; } hash[sum] = i; } return {}; // 题目保证有解,所以这里不会执行 } 这样应该可以解决问题。需要注意的是,哈希表的初始化要放入0:-1,这样可以处理前缀直接为0的情况。例如数组前几个元素为0,如nums=[-3,1,2],那么sum在i=0时是-3,i=1时是-2,i=2时是0。这时候hash中0存在,对应的-1,返回-1+1=0到2,即[0,2],正确。 可能的问题:是否有其他情况需要考虑?比如子数组长度为0?但题目保证至少有一个解,所以无需考虑。另外,是否会有多个重复的前缀?比如多个位置的前缀相同,但哈希表只记录第一个出现的,这样后面的位置遇到同样的前缀时,可以找到最短的子数组吗?不,题目只需要返回任意一个即可,所以没问题。 综上,这个方法是正确的。</think>### 子数组之和为0的解法详解 要解决**为0的子数组**问题,我们可以利用**前缀****哈希表**来高效地找到符合条件的子数组。以下是详细的解决思路代码实现: --- #### **核心思路** 1. **前缀概念**: - 前缀 `prefix_sum[i]` 表示数组前 `i` 个元素。 - 若存在两个不同的下标 `i` `j` 使得 `prefix_sum[i] = prefix_sum[j]`,则子数组 `nums[i+1...j]` 的为0。 2. **哈希表的作用**: - 记录每个前缀**第一次出现的位置**。 - 当某个前缀重复出现时,说明两次出现之间的子数组为0。 --- #### **算法步骤** 1. **初始化哈希表**: - 哈希表初始:`{0: -1}`,表示前缀为0时,下标为-1(处理从数组开头开始的子数组为0的情况)。 2. **遍历数组计算前缀**: - 逐个累加元素,计算当前前缀。 - 若当前前缀已在哈希表中,则直接返回子数组的起始结束下标。 - 否则,将当前前缀及其下标存入哈希表。 --- #### **代码实现** ```cpp #include <vector> #include <unordered_map> using namespace std; vector<int> subarraySum(vector<int> &nums) { unordered_map<int, int> prefix_map; // 哈希表:key为前缀,value为下标 prefix_map[0] = -1; // 初始,处理前缀为0的子数组 int prefix_sum = 0; for (int i = 0; i < nums.size(); i++) { prefix_sum += nums[i]; // 计算当前前缀 // 若前缀已存在,说明找到了为0的子数组 if (prefix_map.find(prefix_sum) != prefix_map.end()) { return {prefix_map[prefix_sum] + 1, i}; } // 记录前缀的首次出现位置 prefix_map[prefix_sum] = i; } return {}; // 题目保证有解,此处不会执行 } ``` --- #### **示例分析** 以输入 `nums = {3, 1, 2, -3, 4}` 为例: 1. **前缀计算**: - i=0: `sum=3` → 存入哈希表。 - i=1: `sum=4` → 存入。 - i=2: `sum=6` → 存入。 - i=3: `sum=3` → 发现i=0的sum相同 → 子数组为[1,3](即元素1,2,-3)。 2. **输出结果**: - 返回 `{1, 3}`。 --- #### **复杂度分析** - **时间复杂度**:$O(n)$,只需一次遍历。 - **空间复杂度**:$O(n)$,哈希表存储最多n个前缀。 --- #### **关键点总结** - **前缀哈希表**:通过记录前缀的首次出现位置,快速定位子数组。 - **边界处理**:初始哈希表 `{0: -1}` 处理从数组开头开始的子数组为0的情况。 此方法高效且直观,能有效解决子数组为0的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值