数组中找到和为给定值的两个数

problem 167 & 170 from leetcode;

https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/

https://leetcode.com/problems/two-sum-iii-data-structure-design/

先来看简单的167:给定一个排好序的数组,以及一个值,找出数组中相加等于该值的两个数,假设这样的值始终存在;

这个只要依次遍历该数组,假设当前值为x,那么只需要在数组中找到value - x;如果存在,直接返回,如果不存在,检查下一个值;因为数组是sorted,所以第二步查找只需要log N的时间;最坏情况是 n * log N;

public int[] twoSum(int[] numbers, int target) {
    int[] result = new int[2];

    for(int i = 1; i <= numbers.length; i++) {
        int x = numbers[i - 1];
        int y = target - x;
        int j = Arrays.binarySearch(numbers, i, numbers.length, y);
        if(j >= i) {
            result[0] = i;
            result[1] = j + 1;
            break;
        }
    }

    return result;
}

题目170要求设计一种数据结构,支持add和find操作,下面是一个例子:

add(1); add(3); add(5);
find(4) -> true
find(7) -> false

一开始我得想法是使用167的解法,add的时候,把输入加入到一个数组中,并且排好序;那么就可以直接使用167的find;但在输入很长的时候,很多的add和find,会TLE;简单的分析一下这种方式,(我使用的是insertion sort), 每次add排序,要O(n), 那么总的时间就是O(n * n);

后来我用AVL树,因为AVL树支持logN的insert/find操作;正好适合这个问题;以下是最终AC的代码:

public class TwoSum {
    List<Integer> numbers = new ArrayList<>();
    AVL avl = new AVL();

    public void add(int number) {
        avl.add(number);
        numbers.add(number);
    }

    public boolean find(int value) {
        for (int x : numbers) {
            int y = value - x;
            Node node = avl.find(y);
            if (node == null) {
                continue;
            }

            //when these two numbers equal, need to make sure there at least two numbers added;
            if (x == y && node.count == 1) {
                continue;
            }

            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        TwoSum twoSum = new TwoSum();

        twoSum.add(1);
        twoSum.add(2);
        System.out.println(twoSum.find(1));
    }

    class AVL {
        Node root;

        private int height(Node root) {
            if (root == null) {
                return -1;
            } else {
                return root.height;
            }
        }

        private Node insert(Node root, int value) {
            if (root == null) {
                root = new Node(value);
            } else if (root.value == value) {
                root.count += 1;
            } else if (root.value < value) {
                //go right;
                root.right = insert(root.right, value);
                if (height(root.right) - height(root.left) == 2) {
                    if (value > root.right.value) {
                        root = singleRotateWithRight(root);
                    } else {
                        root = doubleRotateWithRight(root);
                    }
                }
            } else {
                //go left;
                root.left = insert(root.left, value);
                if (height(root.left) - height(root.right) == 2) {
                    if (value < root.left.value) {
                        root = singleRotateWithLeft(root);
                    } else {
                        root = doubleRotateWithLeft(root);
                    }
                }
            }

            root.height = Math.max(height(root.left), height(root.right)) + 1;
            return root;
        }

        private Node doubleRotateWithRight(Node k3) {
            k3.right = singleRotateWithLeft(k3.right);
            return singleRotateWithRight(k3);
        }

        private Node singleRotateWithRight(Node k2) {
            Node k1 = k2.right;
            k2.right = k1.left;
            k1.left = k2;

            k2.height = Math.max(height(k2.left), height(k2.right)) + 1;
            k1.height = Math.max(height(k1.left), height(k1.right)) + 1;

            return k1;
        }

        private Node doubleRotateWithLeft(Node k3) {
            k3.left = singleRotateWithRight(k3.left);
            return singleRotateWithLeft(k3);
        }

        private Node singleRotateWithLeft(Node k2) {
            Node k1 = k2.left;
            k2.left = k1.right;
            k1.right = k2;

            k2.height = Math.max(height(k2.left), height(k2.right)) + 1;
            k1.height = Math.max(height(k1.left), height(k1.right)) + 1;
            return k1;
        }

        public void add(int value) {
            root = insert(root, value);
        }

        private Node find(Node root, int value) {
            if (root == null) {
                return null;
            }

            if (root.value == value && root.count == 0) {
                return null;
            }

            if (root.value == value) {
                return root;
            }

            if (value > root.value) {
                return find(root.right, value);
            } else {
                return find(root.left, value);
            }
        }

        public Node find(int value) {
            return find(root, value);
        }

        public Node getRoot() {
            return root;
        }
    }

    static class Node {
        final int value;
        int count, height;
        Node left, right;

        Node(int value) {
            this.value = value;
            count = 1;
            height = 0;
        }
    }

}

果然这种方法非常的有效,似乎是Java里面最快的实现了;

BTW, AVL的实现是从教科书里面找出来的,直接去写,真没有这样的本事;

时间: 2024-08-20 07:35:48

数组中找到和为给定值的两个数的相关文章

一个数组中找到满足和为sum的两个数

如果考虑hashmap直接O(n)的速度, 如果不行,就先排序,两头指针很好推理,关键是 a[beg] +a[end]>sum,意思就是说a[end]太大了,最小的数的都不满足,所以排除a[end] 绝知此事要躬行 #include<iostream>#include<algorithm>using namespace std; bool find(int *a,int sum,int len,int &ans1,int &ans2){    int *beg

从数组中选出和等于固定值的n个数(JavaScript实现)

现实生活中的问题,可能会抽象为这样一种数据模型: 从一个数组中挑选出几个数,让这几个数相加的和为指定的值. 大多数读者应该有过网购的经历,网购一般会有个凑单功能,假如读者买了70元的商品,但是必须满100元才能包邮,这时系统会自动推荐一些商品,加起来差不多就100块钱了. 系统如何确定推荐哪些商品呢?这其实就是刚刚提到的模型,我们可以把热销商品的价格放到一个数组中,然后利用算法,找出数组中哪些价格的和为30元. 废话少说,小菜给大家分享一个JavaScript版本的算法实现. 算法代码: 1 f

编程之法section II: 2.2 和为定值的两个数

====数组篇==== 2.2 求和为定值的两个数: 题目描述:有n个整数,找出其中满足两数相加为target的两个数(如果有多组满足,只需要找出其中一组),要求时间复杂度尽可能低. 解法一: 思路:开散列映射,空间换时间, 查找耗时o(n) Writer: zzq Function: 求和为定值的两个数. 方法一: 开散列映射(哈希表). 1) 用哈希表Hashmap先把数组中的数字和对应的下标进行存储,(键,值)=(具体数值,对应下标): 2) 遍历数组,对loss=target-nums[

如何高效地判断数组中是否包含某特定值

 如何检查一个未排序的数组中是否包含某个特定值,这是一个在Java中非常实用并且频繁使用的操作.另外,这也是Stack Overflow上面非常受关注的问题.在得票数最多的答案中,可以看到,检查数组中是否包含特定值可以用多种不同的方式实现,但是时间复杂度差别很大.下面,我将为大家展示各种方法及其需要花费的时间. 1.检查数组中是否包含特定值的四种不同方法 1)使用List: 1 2 3 public static boolean useList(String[] arr, String ta

【C语言】在两个数成对出现的数组中找到一个单独的数。

//在两个数成对出现的数组中找到一个单独的数.比如{1,2,3.3,1,4.2},即找出4 #include <stdio.h> int find(int arr[], int len) { int i = 0; int ret = 0; for (i = 0; i < len; i++) { ret = ret^arr[i]; } return ret; } int main() { int arr1[] = { 1, 2, 2, 3, 1, 5, 3 }; int arr2[] =

在未排序的数组中找到第 k 个最大的元素

在未排序的数组中找到第 k 个最大的元素.请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素. 示例 1: 输入: [3,2,1,5,6,4] 和 k = 2 输出: 5 示例 2: 输入: [3,2,3,1,2,4,5,5,6] 和 k = 4 输出: 4 说明: 你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度.思路方法:这道题思路就挺简单的,考查的就是对排序算法的了解.就用排序算法把数组元素按照降序排列,最后返回排序好的数组中下标为k-1的元素即是答

[LeetCode]1. Two Sum 数组中和为特定值的两个数

Given an array of integers, find two numbers such that they add up to a specific target number. The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that

编程题:用一组数组做函数参数来实现,输入两个数,输出其中最大数

#include<stdio.h> float max(float x,float y) { float z; if(x>y)z=x; else z=y; return z; } void main() { float a[2],c; scanf("%f,%f",&a[0],&a[1]); c=max(a[0],a[1]); printf("%f,%f,the max is %f\n",a[0],a[1],c); } 编程题:用一组

在旋转排序数组之后的数组中找到目标值的位置(很多遍 ,总是晕)

33. Search in Rotated Sorted Array在旋转排序数组中找目标值的位置 int search(vector<int>& nums, int target) { int len=nums.size(); int low=0,high=len-1; while(low<=high){ int mid=(low+high)/2; if(nums[mid]==target){ return mid; } //mid在旋转点左侧 if(nums[mid]<