LeetCode做题笔记
Add two numbers:给定一个数集合和一个数,已知集合中有两个数的和是给定数,求这两个加数的index
方法1:暴力,n^2时间复杂度,不推荐
方法2:快速排序nlogn。按集合里数的两倍与target的大小关系对分。对每一个第一部分的数,在另外一个部分二分搜索第二个数:500~ms
方法3:hash,n的时间复杂度,最高纪录420ms
方法3源码:
/*
* Method 2nd
public void swap(int i, int j, int[] array) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
public final Random RANDOM_INT = new Random();
private int getRondomIndex(int left, int right) {
return RANDOM_INT.nextInt(right - left) + left;
}
public int partition(int left, int right, int array[]){
if (left == right){
return left;
}
//randomized quicksort
swap(right, getRondomIndex(left, right), array);
int i = left;
int j = right - 1;
int partitioner = array[right];
//i = j must be executed
while (i <= j){
//check boundary first
while (i <= right - 1 && array[i] <= partitioner)
i++;
while (j >= 0 && array[j] >= partitioner)
j--;
if (i < j)
swap(i, j, array);
}
if (i < right)
swap(right, i, array);
return i < right - 1 ? i : right - 1;
}
public void quickSort(int left, int right, int[] array){
if (right <= left){
return;
}
//first partition, then quick sort
int q = partition(left, right, array);
quickSort(left, q, array);
quickSort(q + 1, right, array);
}
public int[] twoSum(int[] numbers, int target) {
//index Map
Map<Integer, List<Integer>> indexMap = new HashMap<>();
int numCount = numbers.length;
int[] result = new int[2];
//hash value and indices
for (int i = 0; i < numbers.length; i++){
if (indexMap.get(numbers[i]) == null)
indexMap.put(numbers[i], new ArrayList<Integer>());
indexMap.get(numbers[i]).add(i);
}
for (List<Integer> list : indexMap.values()){
if (list.size() > 1){
//Duplicate value:
//1. 2 * value = target
//2. [exactly one answer] -> no possibility to be answer
if (numbers[list.get(0)] * 2 != target){
for (Integer integer : list){
//Set these integers to be null
numbers[integer] = Integer.MAX_VALUE;
}
numCount -= list.size();
}
else return new int[]{list.get(0) + 1, list.get(1) + 1};
}
}
quickSort(0, numbers.length - 1, numbers);
int boundary = getBounder(numCount, target, numbers);
for (int i = 0; i < boundary; i++){
int temp = binary_search(i, numCount - 1, target - numbers[i], numbers);
if (temp != -1){
int int1 = indexMap.get(numbers[i]).get(0) + 1;
int int2 = indexMap.get(numbers[temp]).get(0) + 1;
if (int1 > int2)
return new int[] {int2, int1};
else {
return new int[] {int1, int2};
}
}
}
return null;
}
public int getBounder(int numCount, int target, int[] numbers){
int i;
for (i = 0; i < numCount; i++){
if (2 * numbers[i] > target)
break;
}
return i;
}
public int binary_search(int left, int right, int key, int[] numbers){
int mid = (left + right) / 2;
if (right < left)
return -1;
if (numbers[mid] == key)
return mid;
if (numbers[mid] > key)
return binary_search(left, mid - 1, key, numbers);
else {
return binary_search(mid + 1, right, key, numbers);
}
}*/
public int[] twoSum(int[] numbers, int target) {
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
int n = numbers.length;
int[] result = new int[2];
for (int i = 0; i < numbers.length; i++)
{
if (map.containsKey(target - numbers[i])) {
result[0] = map.get(target-numbers[i]) + 1;
result[1] = i + 1;
break;
}
else {
map.put(numbers[i], i);
}
}
return result;
}
经验1:对hashMap的get和put都是非常耗时间的,尽量少做
经验2:方法2最好使用随机化快排,效率很高
把两个链表表示的数加起来:最佳624ms,3%, (LeetCode 2, medium)
用长一点的链表做基础,最多只需要new一个新节点
优化建议:进位尽量用数字。如果一个链到头了,另一个没到,应该沿着长链前进。如果进位是0就可以即刻返回,不需要继续前进。
源码:
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
int sum, progress = 0;
ListNode tmp1 = l1, tmp2 = l2;
for (;;){
sum = l1.val + l2.val + progress;
progress = sum >= 10 ? 1 : 0;
l1.val = l2.val = sum >= 10 ? sum - 10 : sum;
if (l1.next == null){
if (l2.next == null){
if (progress == 1)
l2.next = new ListNode(1);
return tmp2;
}
else {
l2 = l2.next;
}
for (; ;){
if (progress == 0)
return tmp2;
sum = l2.val + 1;
progress = sum >= 10 ? 1 : 0;
l2.val = sum >= 10 ? 0 : sum;
if (l2.next == null){
if (progress == 1)
l2.next = new ListNode(1);
break;
}
else
l2 = l2.next;
}
return tmp2;
}
if (l2.next == null){
l1 = l1.next;
for (; ;){
if (progress == 0)
return tmp1;
sum = l1.val + 1;
progress = sum >= 10 ? 1 : 0;
l1.val = sum >= 10 ? sum - 10 : sum;
if (l1.next == null){
if (progress == 1)
l1.next = new ListNode(1);
break;
}
else
l1 = l1.next;
}
return tmp1;
}
l1 = l1.next;
l2 = l2.next;
}
}
经验2:leetcode不靠谱啊,速度不一定对
把一个整数数位逆转,注意符号,不能溢出
最好记录404ms,前5%
public static int reverse(int x) {
StringBuilder string = new StringBuilder(x + "");
int flag = 1;
if (string.charAt(0) == '-'){
flag = -1;
string.reverse().deleteCharAt(string.length()-1);
}
else {
string.reverse();
}
try{
return flag == 1 ? Integer.parseInt(string.toString()) : -1 *Integer.parseInt(string.toString());
}
catch (Exception e){
return 0;
}
}
经验3:类库比较快。而且好像早上/×××以后机器运算比较快?
官方提示:
To check for overflow/underflow, we could checkif ret > 214748364 or ret < –214748364 before multiplying by 10. On theother hand, we do not need to check if ret == 214748364, why? 溢出是2147483647,214748364乘10不溢出
转载于:https://blog.51cto.com/08310302/1597994