标签:
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的实现是从教科书里面找出来的,直接去写,真没有这样的本事;
标签:
原文地址:http://my.oschina.net/u/922297/blog/493164