1. 程式人生 > >LeetCode 315. Count of Smaller Numbers After Self (逆序數對)

LeetCode 315. Count of Smaller Numbers After Self (逆序數對)

You are given an integer array nums and you have to return a new counts array. The counts array has the property where counts[i] is the number of smaller elements to the right of nums[i].

Example:

Given nums = [5, 2, 6, 1]

To the right of 5 there are 2 smaller elements (2 and 1).
To the right of 2 there is only 1
smaller element (1). To the right of 6 there is 1 smaller element (1). To the right of 1 there is 0 smaller element.

Return the array [2, 1, 1, 0].

方法一:窮舉計數,時間複雜度O(n^2),超時、無法通過。

public class Solution {
    public List<Integer> countSmaller(int[] nums) {
        int[] smaller = new int[nums.length];
        for(int i=0; i<nums.length-1; i++) {
            for(int j=i+1; j<nums.length; j++) {
                if (nums[i] > nums[j]) smaller[i] ++;
            }
        }
        List<Integer> results = new ArrayList<>(smaller.length);
        for(int i=0; i<smaller.length; i++) results.add(smaller[i]);
        return results;
    }
}
方法二:從右到左掃描,應用二分法將當前資料插入到前面已排好序的陣列中,二分法查詢的時間複雜度為O(logn),但由於需要插入資料,所以每個資料查詢和插入的總時間是O(nlogn),總體的時間複雜度O(n^2*logn),但勉強能夠通過測試。
public class Solution {
    public List<Integer> countSmaller(int[] nums) {
        int[] smaller = new int[nums.length];
        for(int i=nums.length-2; i>=0; i--) {
            int left = i+1;
            int right = nums.length-1;
            while (left<=right) {
                int m = (left+right)/2;
                if (nums[i] > nums[m]) right = m - 1;
                else left = m + 1;
            }
            smaller[i] = nums.length - left;
            int temp = nums[i];
            for(int j=i; j<right; j++) nums[j] = nums[j+1];
            nums[right] = temp;
        }
        List<Integer> results = new ArrayList<>(nums.length);
        for(int i=0; i<smaller.length; i++) results.add(smaller[i]);
        return results;
    }
}

方法三:應用合併排序。如果我們對陣列進行排序,那麼對於某個特定的資料,其後面的逆序數等於在排序過程中需要移動到該數前面的個數。時間複雜度O(nlogn)。

我們定義陣列pos[i] = j,表示第排名i個數據的元素下標是j。

public class Solution {
    private void sort(int[] nums, int[] smaller, int[] pos, int from, int to) {
        if (from >= to) return;
        int m = (from + to) / 2;
        sort(nums, smaller, pos, from, m);
        sort(nums, smaller, pos, m+1, to);
        int[] merged = new int[to-from+1];
        int i=from, j=m+1, k=0, jump = 0;
        while (i<=m || j<=to) {
            if (i>m) {
                jump ++;
                merged[k++] = pos[j++];
            } else if (j>to) {
                smaller[pos[i]] += jump;
                merged[k++] = pos[i++];
            } else if (nums[pos[i]] <= nums[pos[j]]) {
                smaller[pos[i]] += jump;
                merged[k++] = pos[i++];
            } else {
                jump ++;
                merged[k++] = pos[j++];
            }
        }
        for(int p=0; p<merged.length; p++) pos[from+p] = merged[p];
    }
    public List<Integer> countSmaller(int[] nums) {
        int[] smaller = new int[nums.length];
        int[] pos =new int[nums.length];
        for(int i=0; i<pos.length; i++) pos[i] = i;
        sort(nums, smaller, pos, 0, nums.length-1);
        List<Integer> result = new ArrayList<>(nums.length);
        for(int i=0; i<nums.length; i++) result.add(smaller[i]);
        return result;
    }
}

另一種實現形式:

public class Solution {
    private void sort(int[] nums, int[] pos, int[] counts, int from, int to) {
        if (from+1>=to) return;
        int m=(from+to)/2;
        sort(nums, pos, counts, from, m);
        sort(nums, pos, counts, m, to);
        int[] merged = new int[to-from];
        int smaller = 0;
        for(int i=from, j=m, k=0; k<merged.length; k++) {
            if (i>=m) {
                merged[k] = pos[j++];
            } else if (j>=to) {
                counts[pos[i]] += smaller;
                merged[k] = pos[i++];
            } else if (nums[pos[i]] <= nums[pos[j]]) {
                counts[pos[i]] += smaller;
                merged[k] = pos[i++];
            } else {
                smaller ++;
                merged[k] = pos[j++];
            }
        }
        for(int i=0; i<merged.length; i++) pos[from+i] = merged[i];
    }
    public List<Integer> countSmaller(int[] nums) {
        int[] counts = new int[nums.length];
        int[] pos = new int[nums.length];
        for(int i=0; i<pos.length; i++) pos[i] = i;
        sort(nums, pos, counts, 0, nums.length);
        List<Integer> results = new ArrayList<>(nums.length);
        for(int count : counts) results.add(count);
        return results;
    }
}


方法四:使用BST進行統計。時間複雜度O(nlogn)。可以先對陣列排序,以便使BST均衡?

public class Solution {
    TreeNode root;
    private int smaller(TreeNode current, int val) {
        current.size ++;
         if (current.val < val) {
             if (current.right == null) current.right = new TreeNode(val);
             return current.size - 1 - current.right.size + smaller(current.right, val);
         } else if (current.val > val) {
             if (current.left == null) current.left = new TreeNode(val);
             return smaller(current.left, val);
         } else {
             return current.left == null? 0 : current.left.size;
         }
    }
    public List<Integer> countSmaller(int[] nums) {
        List<Integer> result = new ArrayList<>(nums.length);
        int[] smaller = new int[nums.length];
        if (nums == null || nums.length == 0) return result;
        root = new TreeNode(nums[nums.length-1]);
        for(int i=nums.length-1; i>=0; i--) {
            smaller[i] = smaller(root, nums[i]);
        }
        for(int i=0; i<smaller.length; i++) result.add(smaller[i]);
        return result;
    }
}
class TreeNode {
    int val;
    int size;
    TreeNode left, right;
    TreeNode(int val) {
        this.val = val;
    }
}

事實上,二叉搜尋樹可以用陣列實現:

public class Solution {
    private void update(int[] tree, int[] smaller, int value) {
        int i=0, j=tree.length-1;
        while (i<=j) {
            int m = (i+j)/2;
            if (value < tree[m]) {
                smaller[m] ++;
                j = m - 1;
            } else {
                i = m + 1;
            }
        }
    }
    private int smaller(int[] tree, int[] smaller, int value) {
        int sum = 0;
        int i=0, j=tree.length-1;
        while (i<=j) {
            int m = (i+j)/2;
            if (tree[m] <= value) {
                sum += smaller[m];
                i = m + 1;
            } else {
                j = m - 1;
            }
        }
        return sum;
    }
    public List<Integer> countSmaller(int[] nums) {
        int[] tree = Arrays.copyOf(nums, nums.length);
        Arrays.sort(tree);
        int[] smaller = new int[nums.length];
        int[] count = new int[nums.length];
        for(int i=nums.length-1; i>=0; i--) {
            count[i] = smaller(tree, smaller, nums[i]);
            update(tree, smaller, nums[i]);
        }
        List<Integer> results = new ArrayList<>(nums.length);
        for(int i=0; i<count.length; i++) results.add(count[i]);
        return results;
    }
}

甚至再進一步簡化:

public class Solution {
    private int smaller(int[] tree, int[] smaller, int value) {
        int sum = 0;
        int i=0, j=tree.length-1;
        while (i<=j) {
            int m = (i+j)/2;
            if (tree[m] <= value) {
                sum += smaller[m];
                i = m + 1;
            } else {
                smaller[m] ++;
                j = m - 1;
            }
        }
        return sum;
    }
    public List<Integer> countSmaller(int[] nums) {
        int[] tree = Arrays.copyOf(nums, nums.length);
        Arrays.sort(tree);
        int[] smaller = new int[nums.length];
        int[] count = new int[nums.length];
        for(int i=nums.length-1; i>=0; i--) {
            count[i] = smaller(tree, smaller, nums[i]);
        }
        List<Integer> results = new ArrayList<>(nums.length);
        for(int i=0; i<count.length; i++) results.add(count[i]);
        return results;
    }
}

上面判斷條件中,tree[m] <= value修改為tree[m] < value會更加make sense:

public class Solution {
    private int smaller(int[] tree, int[] count, int value) {
        int sum = 0;
        int i = 0, j = tree.length - 1;
        while (i <= j) {
            int m = (i + j) / 2;
            if (tree[m] < value) {
                sum += count[m];
                i = m + 1;
            } else {
                count[m]++;
                j = m - 1;
            }
        }
        return sum;
    }
    public List<Integer> countSmaller(int[] nums) {
        int[] tree = Arrays.copyOf(nums, nums.length);
        Arrays.sort(tree);
        int[] count = new int[nums.length];
        Integer[] result = new Integer[nums.length];
        for(int i = nums.length - 1; i >= 0; i--) {
            result[i] = smaller(tree, count, nums[i]);
        }
        return Arrays.asList(result);
    }
}

如果先用集合排除重複的數字,則資料量可以縮減:
public class Solution {
    private int smaller(int[] tree, int[] count, int value) {
        int sum = 0;
        int i = 0, j = tree.length - 1;
        while (i <= j) {
            int m = (i + j) / 2;
            if (tree[m] < value) {
                sum += count[m];
                i = m + 1;
            } else {
                count[m]++;
                j = m - 1;
            }
        }
        return sum;
    }
    public List<Integer> countSmaller(int[] nums) {
        Set<Integer> unique = new HashSet<>();
        for(int num : nums) unique.add(num);
        int[] tree = new int[unique.size()];
        int pos = 0;
        for(int num : unique) tree[pos++] = num;
        Arrays.sort(tree);
        int[] count = new int[nums.length];
        Integer[] result = new Integer[nums.length];
        for(int i = nums.length - 1; i >= 0; i--) {
            result[i] = smaller(tree, count, nums[i]);
        }
        return Arrays.asList(result);
    }
}

方法五:使用分段樹。時間複雜度O(nlogn)。
public class Solution {
    private int smaller(Node node, int val) {
        node.count ++;
        if (node.min == node.max) return 0;
        int m = (node.min + node.max) / 2;
        if (m < val) {
            if (node.right == null) node.right = new Node(m+1, node.max);
            return node.count - 1 - node.right.count + smaller(node.right, val);
        } else if (m > val) {
            if (node.min == m) return 0;
            if (node.left == null) node.left = new Node(node.min, m-1);
            return smaller(node.left, val);
        } else {
            if (node.left == null) return 0;
            return node.left.count;
        }
    }
    public List<Integer> countSmaller(int[] nums) {
        int min = Integer.MAX_VALUE;
        int max = Integer.MIN_VALUE;
        for(int num: nums) {
            min = Math.min(min, num);
            max = Math.max(max, num);
        }
        Node root = new Node(min, max);
        int[] smaller = new int[nums.length];
        for(int i=nums.length-1; i>=0; i--) {
            smaller[i] = smaller(root, nums[i]);
        }
        List<Integer> result = new ArrayList<>(nums.length);
        for(int i=0; i<smaller.length; i++) result.add(smaller[i]);
        return result;
    }
}
class Node {
    int min, max;
    int count;
    Node left, right;
    Node(int min, int max) {
        this.min = min;
        this.max = max;
    }
}

注意,關於分段樹此處可能有概念誤解,分段樹應該是按照名次進行分段,即等同於樹狀陣列,以後再具體檢查修正。

方法六:使用樹狀陣列,要點是按名次進行計數。時間複雜度O(nlogn)。

public class Solution {
    private void sort(int[] nums, int[] pos, int from, int to) {
        if (from>=to) return;
        int m = (from+to)/2;
        sort(nums, pos, from, m);
        sort(nums, pos, m+1, to);
        int[] merged = new int[to-from+1];
        int i=from, j=m+1, p=0;
        while (i<=m || j<=to) {
            if (i>m) {
                merged[p++] = pos[j++];
            } else if (j>to) {
                merged[p++] = pos[i++];
            } else if (nums[pos[i]] <= nums[pos[j]]) {
                merged[p++] = pos[i++];
            } else {
                merged[p++] = pos[j++];
            }
        }
        for(int k=0; k<merged.length; k++) pos[from+k] = merged[k];
    }
    private int count(int[] sum, int s) {
        int count = 0;
        while (s>0) {
            count += sum[s];
            s -= (s & -s);
        }
        return count;
    }
    private void update(int[] sum, int s) {
        while (s<sum.length) {
            sum[s] ++;
            s += (s & -s);
        }
    }
    public List<Integer> countSmaller(int[] nums) {
        int[] pos = new int[nums.length];
        for(int i=0; i<nums.length; i++) pos[i] = i;
        sort(nums, pos, 0, nums.length-1);
        int[] seq = new int[nums.length];
        for(int i=0, s=0; i<pos.length; i++) {
            if (i==0 || nums[pos[i]] != nums[pos[i-1]]) seq[pos[i]] = ++ s; else seq[pos[i]] = s;
        }
        int[] sum = new int[nums.length+1];
        int[] smaller = new int[nums.length];
        for(int i=nums.length-1; i>=0; i--) {
            smaller[i] = count(sum, seq[i]-1);
            update(sum, seq[i]);
        }
        List<Integer> result = new ArrayList<>(nums.length);
        for(int i=0; i<smaller.length; i++) result.add(smaller[i]);
        return result;
    }
}


相關推薦

LeetCode 315. Count of Smaller Numbers After Self 序數

You are given an integer array nums and you have to return a new counts array. The counts array has the property where counts[i] is t

Leetcode 315. Count of Smaller Numbers After Self

個數 初始 tor ktr href number .get numbers cto Problem: You are given an integer array nums and you have to return a new counts array. The

leetcode [Divide and Conquer] No.315 Count of Smaller Numbers After Self

題目描述 You are given an integer array nums and you have to return a new counts array. The counts array has the property where counts

315. Count of Smaller Numbers After Self

turn amp for tsm tail index you code merge p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px "Helvetica Neue"; color: #323333 } p.p2 {

[Week 2] LeetCode 335. Count of Smaller Numbers After Self

LeetCode 335. Count of Smaller Numbers After Self 問題描述: You are given an integer array nums and you have to return a new counts a

[LeetCode] Count of Smaller Numbers After Self 計算後面較小數字的個數

You are given an integer array nums and you have to return a new counts array. The counts array has the property where counts[i] is the number of smaller

LeetCode315 Count of Smaller Numbers After Self

Count of Smaller Numbers After Self You are given an integer array nums and you have to return a new counts array. The counts array has the pr

[Swift]LeetCode315. 計算右側小於當前元素的個數 | Count of Smaller Numbers After Self

sort sel 當前 元素 prop 計算 spa earch rep You are given an integer array nums and you have to return a new countsarray. The counts array has t

LeetCode 985 Sum of Even Numbers After Queries 解題報告

self mon 一個 val span class for return pan 題目要求 We have an array A of integers, and an array queries of queries. For the i-th query val =

#Leetcode# 985. Sum of Even Numbers After Queries

should mono eve base -a out spa tco after https://leetcode.com/problems/sum-of-even-numbers-after-queries/ We have an array A of inte

leetcode】985. Sum of Even Numbers After Queries

leetcode 執行 pre code self urn type sel gin 題目如下: We have an array A of integers, and an array queries of queries. For the i-th query val

[LeetCode] Maximum Product of Three Numbers

clas style find leet 數組元素 cat 兩個 bit bsp Given an integer array, find three numbers whose product is maximum and output the maximum produ

[leetcode]633. Sum of Square Numbers

body ges sum pre -- mat sqrt else 註意 雙指針比較簡單的應用,搜索範圍要註意 public boolean judgeSquareSum(int c) { /* 雙指針,搜索範圍是0到sqrt(c)

leetcode:(633) Sum Of Square Numbers(java)

題目:        Given a non-negative integer c, your task is to decide whether there're two integers a and b 

[LeetCode] 633. Sum of Square Numbers

題目 Given a non-negative integer c, your task is to decide whether there’re two integers a and b such that a2 + b2 = c. Example 1:

[LeetCode] Maximum XOR of Two Numbers in an Array 陣列中異或值最大的兩個數字

Given a non-empty array of numbers, a0, a1, a2, … , an-1, where 0 ≤ ai < 231. Find the maximum result of ai XOR aj, where 0 ≤ i, j < n. Could you

[LeetCode] Maximum Product of Three Numbers 三個數字的最大乘積

Given an integer array, find three numbers whose product is maximum and output the maximum product. Example 1: Input: [1,2,3] Output: 6 Example 2

[Swift Weekly Contest 122]LeetCode985. 查詢後的偶數和 | Sum of Even Numbers After Queries

提示 out each eat 永久 bind put mono solution We have an array A of integers, and an array queries of queries. For the i-th query val = quer

Leetcode——633. Sum of Square Numbers

題目原址 題目描述 Given a non-negative integer c, your task is to decide whether there’re two integers

Sum of Even Numbers After Queries

inf sum 分享圖片 ber numbers alt 技術分享 ima info Solution: Sum of Even Numbers After Queries