LintCode--twoSum

题目

给一个整数数组,找到两个数使得他们的和等于一个给定的数 target。

你需要实现的函数twoSum需要返回这两个数的下标, 并且第一个下标小于第二个下标。注意这里下标的范围是 1 到 n,不是以 0 开头。

思路

这道题目是找到数组中和为指定值的两个元素,需要遍历每个值num,判断数组是否包含(target-num),并且(target-num)和num不是同一个数。

算法实现

方法1:O(n^2)

如果不考虑算法时间复杂度,可以使用最简单易行的方式进行实现。

public class Solution {
    /*
     * @param numbers: An array of Integer
     * @param target: target = numbers[index1] + numbers[index2]
     * @return: [index1 + 1, index2 + 1] (index1 < index2)
     */
    public int[] twoSum(int[] numbers, int target) {
        // write your code here
        for(int i = 0 ; i < numbers.length - 1; i++)
        {
            for(int j = i+1; j < numbers.length; j++)
            {
                if(numbers[i]+numbers[j] == target)
                {
                    return new int[]{i+1, j+1};
                }
            }
        }
        
        throw new IllegalArgumentException("no such sum");
    }
}
方法2:O(n)

根据算法思路可知,需要判断数组中是否包含某元素以及获取元素的角标。而对于数组对象来说,并没有此功能,因此可以将数组转换成List集合,并使用集合的indexOf方法进行编写。

public class Solution {
    /*
     * @param numbers: An array of Integer
     * @param target: target = numbers[index1] + numbers[index2]
     * @return: [index1 + 1, index2 + 1] (index1 < index2)
     */
    public int[] twoSum(int[] numbers, int target) {
        // write your code here
        ArrayList<Integer> al = new ArrayList<Integer>();
        
        for(int i = 0; i < numbers.length; i++)
        {
            al.add(numbers[i]);
        }
        
        //遍历集合
        for(int i = 0; i < al.size(); i++)
        {
            int num1 = al.get(i);
            int num2 = target - num1;
            
            //如果集合中包含(target-遍历的值)
            if(al.contains(num2))
            {
                if(num1 != num2)
                {
                    return new int[]{i+1, al.indexOf(num2)+1};
                }
                else
                {
                    //如果两个元素相同,需要判断数值中是否包含两个相同的元素
                    int index1 = al.indexOf(num1);
                    if(index1 != al.size()-1)
                    {
                        List<Integer> list = al.subList(index1+1, al.size());
                        int index2 = list.indexOf(num1);
                        
                        //如果数组包含两个相同的元素并且和是target
                        if(index2 != -1)
                        {
                            return new int[]{index1+1, index1+index2+2};
                        }
                    }
                }
                
            }
        }
        
        throw new IllegalArgumentException("no such sum");
    }
}
方法3:O(n)

方法2中使用ArrayList集合实现此功能,代码较为复杂,并且需要创建多个集合,占用内存空间较大,所以进行改进,使用Map集合实现,此方法使用HashMap。

HashMap集合中的键是唯一的,在使用put(key, value)方法添加新元素时,会调用key.hashCode()计算hash值,如果集合中有hash值相同的键,会继续调用key.equals(HashMap.e)判断HashMap集合中是否包含和key相同的键,如果有就会使用新的值替换旧的值。

将数组中元素和角标作为映射对存入HashMap集合时,如果有重复出现的数值,那么它在Map集合中对应的值是其在数组中最后一次出现的角标。

public class Solution {
    /*
     * @param numbers: An array of Integer
     * @param target: target = numbers[index1] + numbers[index2]
     * @return: [index1 + 1, index2 + 1] (index1 < index2)
     */
    public int[] twoSum(int[] numbers, int target) {
        // write your code here
        HashMap<Integer, Integer> hm = new HashMap<Integer, Integer>();
        
        //将元素和角标存入Map集合
        //对于重复的元素,其在Map集合中对应的值是其在数组中最后一次出现的角标
        for(int i = 0; i < numbers.length; i++)
        {
            hm.put(numbers[i], i);
        }
        
        //遍历数组
        for(int i = 0; i < numbers.length; i++)
        {
            int temp = target - numbers[i];
            
            //当集合中包含temp值时,并且其角标和numbers[i]不相同,意味着temp和numbers[i]不是同一个数
            //返回数组
            if(hm.containsKey(temp) && hm.get(temp) != i)
            {
                return new int[]{i+1, hm.get(temp)+1};
            }
        }
        
        throw new IllegalArgumentException("no such sum");
    }
}

错误总结

1、字符串的长度是一个方法,length(),数组的长度是属性,length。注意区分

2、对于传入的字符串和数组,需要考虑其是否是空的情况。

3、Arrays.asList(T... a)和subList(from, to)返回的都是List集合,是多态。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值