leetcode 数组array

 

二维数组初始化:

int[][] a = {{1,3},{2,6},{8,10},{15,18}};


120. Triangle

给出一个三角形(数据数组),找出从上往下的最小路径和。每一步只能移动到下一行中的相邻结点上。

解法,自底向上

The idea is simple.

  1.  Go from bottom to top.

  2.  We start form the row above the bottom row [size()-2].

  3.  Each number add the smaller number of two numbers that below it.

  4.  And finally we get to the top we the smallest sum.

  public int minimumTotal(List<List<Integer>> triangle) {
        for(int i = triangle.size() - 2; i >= 0; i--)
            for(int j = 0; j <= i; j++)
                triangle.get(i).set(j, triangle.get(i).get(j) + Math.min(triangle.get(i + 1).get(j), triangle.get(i + 1).get(j + 1)));
        return triangle.get(0).get(0);
    }

 

Boyer-Moore majority vote algorithm(摩尔投票算法)

简介

Boyer-Moore majority vote algorithm(摩尔投票算法)是一种在线性时间O(n)和空间复杂度的情况下,在一个元素序列中查找包含最多的元素。它是以Robert S.Boyer和J Strother Moore命名的,1981年发明的,是一种典型的流算法(streaming algorithm)。

在它最简单的形式就是,查找最多的元素,也就是在输入中重复出现超过一半以上(n/2)的元素。如果序列中没有最多的元素,算法不能检测到正确结果,将输出其中的一个元素之一。

当元素重复的次数比较小的时候,对于流算法不能在小于线性空间的情况下查找频率最高的元素。

算法描述

算法在局部变量中定义一个序列元素(m)和一个计数器(i),初始化的情况下计数器为0. 算法依次扫描序列中的元素,当处理元素x的时候,如果计数器为0,那么将x赋值给m,然后将计数器(i)设置为1,如果计数器不为0,那么将序列元素m和x比较,如果相等,那么计数器加1,如果不等,那么计数器减1。处理之后,最后存储的序列元素(m),就是这个序列中最多的元素。

如果不确定是否存储的元素m是最多的元素,还可以进行第二遍扫描判断是否为最多的元素。

perudocode

  • Initialize an element m and a counter i with i = 0
  • For each element x of the input sequence:
    • if i = 0, then assign m = x and i = 1
    • else if m = x, then assign i = i + 1
    • else assign i = i − 1
  • Return m

问题1:数组中存在元素出现次数大于 ⌊ n/2 ⌋ ,求该元素

上面方法即可

问题2:数组中是否存在元素出现次数大于 ⌊ n/2 ⌋ 

用上面找到的摩尔投票算法,第一遍扫描输出一个存储的元素,然后还需要进行第二遍扫描来判断元素在序列中是否确实超过n/2了。 因为一个元素超过一半,最后肯定会留下,但是最后留下的不一定超过一半,所以要扫描第二遍。

 

229. Majority Element II

求出现次数大于n/3的众数,而且限定了时间和空间复杂度,那么就不能排序,也不能使用哈希表,这么苛刻的限制条件只有一种方法能解了,那就是摩尔投票法 Moore Voting

我们先考虑可能会有多少个众数,经过举了很多例子分析得出,任意一个数组出现次数大于n/3的众数最多有两个

我们使用投票法的核心是找出两个候选众数进行投票,需要两遍遍历,第一遍历找出两个候选众数,第二遍遍历重新投票验证这两个候选众数是否为众数即可,选候选众数方法和前面那篇Majority Element 求众数一样,由于之前那题题目中限定了一定会有众数存在,故而省略了验证候选众数的步骤,这道题却没有这种限定,即满足要求的众数可能不存在,所以要有验证。

public List<Integer> majorityElement(int[] nums) {
    if (nums == null || nums.length == 0)
        return new ArrayList<Integer>();
    List<Integer> result = new ArrayList<Integer>();
    int number1 = nums[0], number2 = nums[0], count1 = 0, count2 = 0, len = nums.length;
    for (int i = 0; i < len; i++) {
        if (nums[i] == number1)
            count1++;
        else if (nums[i] == number2)
            count2++;
        else if (count1 == 0) {
            number1 = nums[i];
            count1 = 1;
        } else if (count2 == 0) {
            number2 = nums[i];
            count2 = 1;
        } else {
            count1--;//不属于这两个,都要减一
            count2--;
        }
    }
    count1 = 0;
    count2 = 0;
    for (int i = 0; i < len; i++) {
        if (nums[i] == number1)
            count1++;
        else if (nums[i] == number2)
            count2++;
    }
    if (count1 > len / 3)
        result.add(number1);
    if (count2 > len / 3)
        result.add(number2);
    return result;
}

 

旋转数组的最小数字

采用二分法解答这个问题,
mid = low + (high - low)/2
需要考虑三种情况:
(1)array[mid] > array[high]:
出现这种情况的array类似[3,4,5,6,0,1,2],此时最小数字一定在mid的右边。
low = mid + 1
(2)array[mid] == array[high]:
出现这种情况的array类似 [1,0,1,1,1] 或者[1,1,1,0,1],此时最小数字不好判断在mid左边
还是右边,这时只好一个一个试 ,
high = high - 1
(3)array[mid] < array[high]:
出现这种情况的array类似[2,2,3,4,5,6,6],此时最小数字一定就是array[mid]或者在mid的左
边。因为右边必然都是递增的。
high = mid
注意这里有个坑:如果待查询的范围最后只剩两个数,那么mid 一定会指向下标靠前的数字
比如 array = [4,6]
array[low] = 4 ;array[mid] = 4 ; array[high] = 6 ;
如果high = mid - 1,就会产生错误, 因此high = mid
但情形(1)中low = mid + 1就不会错误

import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        int low = 0 ; int high = array.length - 1;   
        while(low < high){
            int mid = low + (high - low) / 2;        
            if(array[mid] > array[high]){
                low = mid + 1;
            }else if(array[mid] == array[high]){
                high = high - 1;
            }else{
                high = mid;
            }   
        }
        return array[low];
    }
}

 

//旋转二分查找目标值
    public int search(int[] nums, int target) {
        int length=nums.length;
        if(length<=0) return -1;
        int low=0;
        int high=length-1;
        int mid=-1;
        while (low<=high){
            mid=(low+high)/2;
            if(target==nums[mid]) {
                return mid;
            }else {
                if(nums[mid]<nums[high]){
                    if(nums[mid]<target&&nums[high]>=target) low=mid+1;
                    else high=mid-1;
                }else {
                    if(nums[low]<=target&&nums[mid]>target) high=mid-1;
                    else low=mid+1;
                }
            }
        }
        return -1;
    }
}

 

任务列表(360公司2017春招真题)

现在现在有一台机器,这台机器可以接收两种形式任务:(1)任务列表,任务列表里面有N个任务,对于第i个任务,机器在Ti时间开始执行,并在1个单位时间内做完。(2)临时任务,机器可以在任意时间接收一个临时任务,但任务列表里面的任务优先级要高于临时任务,也就是说当机器空闲的时候才会执行临时任务。

现在机器已经接收一个任务列表。接下来会有M个临时任务,我们想知道每个临时任务何时被执行。为了简化问题我们可以认为这M个临时任务是独立无关即任务是可以同时执行的,互不影响的。

输入
输入数据有多组,每组数据第一行包括两个整数N和M(1<=N, M<=10^5)。
接下来一行有N个不同数字T1,T2,T3.....TN(1<=T1
接下来又M行,每行一个数字Qi(1<=Qi<=10^9),表示第i个临时任务的的接收时间。
输出
对于每个临时任务,输出它被执行的时间。
样例输入
5 6
1 2 3 5 6
3
2
1
4
5
6
样例输出
4
4
4
4
7

7

将不能执行的时间标出来 对于每个临时任务往后找出一个可以执行的时间

    public static void main(String[] args) {

        Scanner cin = new Scanner(System.in);
        int n = cin.nextInt();
        int m = cin.nextInt();
        int[] gap = new int[100000];
        for (int i = 0; i < n; i++) {
            int temp = cin.nextInt();
            gap[temp] = 1;
        }
        int[] result = new int[m];
        for (int i = 0; i < m; i++) {
            int temp = cin.nextInt();

            for (int j = temp; j < gap.length; j++) {
                if (gap[j] != 1) {
                    result[i] = j;
                    break;
                }
            }

        }

        for (int i = 0; i < result.length; i++) {
            System.out.println(result[i]);
        }

    }

 

56. Merge Intervals

先把第一个区间加入结果集,在循环中如果更新了第一个区间的max interval[1],result的第一个interval也会随之更新

 

public int[][] merge(int[][] intervals) {
        if (intervals.length <= 1)
            return intervals;

        // Sort by ascending starting point
        Arrays.sort(intervals, (i1, i2) -> Integer.compare(i1[0], i2[0]));

        List<int[]> result = new ArrayList<>();
        int[] newInterval = intervals[0];
        result.add(newInterval);
        for (int[] interval : intervals) {
            if (interval[0] <= newInterval[1]) // Overlapping intervals, move the end if needed
                newInterval[1] = Math.max(newInterval[1], interval[1]);
            else {                             // Disjoint intervals, add the new interval to the list
                newInterval = interval;
                result.add(newInterval);
            }
        }

        return result.toArray(new int[result.size()][]);
    }

 

posted @ 2018-07-25 16:25  喵喵帕斯  阅读(192)  评论(0编辑  收藏  举报