• 算法---------两数之和


    给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
    
    你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
    
    示例:
    
    给定 nums = [2, 7, 11, 15], target = 9
    
    因为 nums[0] + nums[1] = 2 + 7 = 9
    所以返回 [0, 1]
    

    我的解答:

    class Solution {
        public int[] twoSum(int[] nums, int target) {
            int length = nums.length;
            //i j  首位两个数字
            for (int i = 0 ,j = length -1;i < j ;i++,j--){
                if (nums[i] + nums[j] == target) {
                    return new int[]{i,j};
                }
                    // k 是i 后面的一位
                for (int k = i +1; k < j; k++){
                    //  如果满足条件  返回   否则k 移动
                    if (nums[i] + nums[k] == target){
                        return new int[]{i,k};
                    }else if (nums[j] + nums[k] == target){
                        return new int[]{k,j};
                    }
                }
                // 全都不满足条件  ij 移动
    
            }
    
            return null;
        }
    }
    

    网上最快的解答:

    class Solution {
       int size = 2048;
    	int[] map = new int[size];
    	int length = 2047;
    	int index;
        
        public int[] twoSum(int[] nums, int target) {
        	for (int i = 0; i < nums.length; i++) {
    			index = nums[i]&length; //
    
    			if (map[index] != 0) {
    				return new int[] { map[index] - 1, i };
    			} else {
    				map[(target - index)&length ] = i + 1;
    			}
    		}
    		throw new IllegalArgumentException("No two sum solution");
        }
    }
    

    这个算法我看了大概三天(因为我还要工作,没有大块的时间去研究),花了图,转换成二进制,才终于明白作者的大概意思。
    当然,同时也看出了这个算法的漏洞。
    比如:

    twoSum(new int[]{2047,0, 800001, 800000, 7,2,2048}, 4095);
    

    返回的结果是[0,1],第0个元素和第一个元素,相加显然不等于4095.

    作者大概的执行思路是:

    1100 0011 0101 0000 0000  800000  num[i]	
    		    111 1111 1111   2047  length
    		    101 0000 0000   1280   index
    		   
    		   
    		   
    1 1000 0110 1010 0000 0000    target 1600000	
    			 101 0000 0000  index
    1 1000 0110 0101 0000 0000   target -index
    			 111 1111 1111   2047  length
    			 
    			 
    			 101 0000 0000			 
    

    补充:2047 二进制是11111111111 (11个1)

    首先取出一个数,然后让这个数num[i]&2047 = a

    之后取判断map[a]是不是0(存不存在),如果不是0(存在的话)就直接返回这个数的索引,和存在的map 里面的索引。

    如果不存在,就让target - num[i] ,然后&2047(11个1)。

    漏洞分析:

    在作者的思想里,11位就可以确定一个数字,同时也认为,target 减去这个数之后的11 也可以确定是一个数。其实是错误的。23位到11这区间的数据,作者没有关心。这算法从这里看就是有漏洞的。我们就从23位到11位之间做文章,就可以得到这个算法的漏洞。

    比如在做着的算法里,0 和2048(100000000000) 是一个数字 因为,最后11位都是0. 根据这个漏洞去反推作者的算法。
    目标数 1111 1111 1111 (4095)
    我找的数组的第一个数是 111 1111 1111 (2047)
    1111 1111 1111 (4095) - 111 1111 1111 (2047) = 100000000000
    然后和11111111111 做& 运算之后的数字是0
    这时候如果第二个数字是0,就直接返回了0 和 2048,根本不是target 4095

    比如

    twoSum(new int[]{2047,0, 800001, 800000, 7,2,2048}, 4095);
    

    这个结果应该是0,6, 但是按照网上最快的,返回是0,1。
    是因为:
    首先,第一个数2047是
    111111111111(11个1) & 2047 等于 2047(11个1)

    然后targe(4095 ) - 2047 相当于 111111111111(12个) - 11111111111(11个1) = 100000000000 (应该是2048)

    然后把这个数100000000000 (2048) & 2047 = 0

    然后把map[0] = 1

    到第二个数的时候,0 & 2047 = 0 ,发现这个数存在,就取出来返回。结果两个数之后是2047 ,根本不是我想要的4095

  • 相关阅读:
    Android 使用EventBus进行Fragment和Activity通信
    Android 实现对多个EditText的监听
    Retrofit2.0动态url遇到的坑
    Android 轻松实现语音朗读
    Android 7.0 因为file://引起的FileUriExposedException异常
    Android拍照得到全尺寸图片并进行压缩/拍照或者图库选择 压缩后 图片 上传
    Toolbar自定义布局
    [致歉]2:05-6:35部分站点出现故障,给您带来麻烦,请谅解团队
    上周热点回顾(8.11-8.17)团队
    [网站公告]8月17日14:00-15:00(周日下午)发布新版站内短消息团队
  • 原文地址:https://www.cnblogs.com/caoxinyu/p/10568465.html
Copyright © 2020-2023  润新知