leetcode-pp / 91alg-5-daily-check

91 天学算法第五期打卡
55 stars 14 forks source link

【Day 39 】2021-10-18 - 762.Number Stream to Intervals #56

Open azl397985856 opened 3 years ago

azl397985856 commented 3 years ago

762.Number Stream to Intervals

入选理由

暂无

题目地址

https://binarysearch.com/problems/Triple-Inversion

前置知识

Constraints

n ≤ 100,000 where n is the length of nums Example 1 Input nums = [7, 1, 2] Output 2 Explanation We have the pairs (7, 1) and (7, 2)

thinkfurther commented 3 years ago

思路

在排序好的list里,找到比3倍小的数,然后结果加上比3倍大的数。并把该数插入排序好的list里

代码

from sortedcontainers import SortedList
class Solution:
    def solve(self, A):
        sorted_list = SortedList()
        result = 0
        for n in A:
            smallerNumbers = bisect.bisect_right(sorted_list, n * 3)
            biggerNumbers = len(sorted_list) - smallerNumbers
            result += biggerNumbers
            sorted_list.add(n)
        return result

复杂度

时间复杂度 :O(Nlog N)

空间复杂度:O(N)

JK1452470209 commented 3 years ago

思路

遍历数组,用TreeMap存储已经遍历过的元素和元素出现的个数,用tailMap(K fromKey, boolean inclusive)寻找所有满足条件的值,将值的总和加到结果中。

代码

class Solution {
    public int solve(int[] nums) {
        if (nums.length == 0) return 0;
        int res = 0;
        TreeMap<Integer, Integer> map = new TreeMap<>();
        map.put(nums[0], 1);
        for (int i = 1; i < nums.length; i++) {
            Map<Integer, Integer> candidates = map.tailMap(3 * nums[i], false);
            for (Map.Entry<Integer, Integer> entry: candidates.entrySet()) {
                res += entry.getValue();
            }
            map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
        }
        return res;        
    }
}

复杂度

时间复杂度:O(NlogN)

空间复杂度:O(N)

laurallalala commented 3 years ago

代码

class Solution:
    def solve(self, nums):
        d = SortedList()
        res = 0

        for i in range(len(nums)):
            idx = d.bisect_right(d, nums[i]*3)
            res += len(nums) - idx
            d.add(nums[i])

        return res

复杂度

user1689 commented 3 years ago

题目

https://binarysearch.com/problems/Triple-Inversion

思路

binarySearch, mergeSort

python3

import bisect
class Solution:
    # 思路一
    # 二分
    def solve(self, nums):
        ans = 0
        tmp = []
        for a in nums:
            i = bisect.bisect_right(tmp, a * 3)
            ans += len(tmp) - i
            bisect.insort_right(tmp, a)
        return ans

class Solution:
    def solve(self, nums):

        # time nlogn
        # space n
        # mergeSort
        self.count = 0

        def divide(low, high):
            if (low < high):
                mid = low + (high - low) // 2
                divide(low, mid)
                divide(mid + 1, high)
                merge(low, mid, high)

        def merge(low, mid, high):

            tmp = []
            i, j = low, mid + 1
            while i <= mid and j <= high:
                if (nums[i] <= nums[j]):
                    tmp.append(nums[i])
                    i += 1
                elif (nums[i] > nums[j]):
                    tmp.append(nums[j])
                    j += 1

            # 归并排序保证了一定有ti < tj
            # eg: 
            # ti    tj
            # [1,7] [2,5]
            # 1和2对比 ti+=1 (当1<3*2说明得在1当中继续找更得数看看会不会大于3*2,所以ti往后移)
            # 7和2对比 tj+=1 (7>3*2 计数器+1 然后tj往后移看是否还存在7>3*nums[tj]的情况)
            # 7和5对比 ti+=1 (7<3*5 7为左边数组最大的元素了,如果它都不大于3*nums[tj],就不可能再有更大的了,所以退出循环,计数完成)

            ti, tj = low, mid + 1
            while ti <= mid and tj <= high:
                if (nums[ti] <= (3 * nums[tj])):
                    ti += 1
                elif (nums[ti] > (3 * nums[tj])):
                    self.count += mid - ti + 1
                    tj += 1

            while (i <= mid):
                tmp.append(nums[i])
                i += 1

            while (j <= high):
                tmp.append(nums[j])
                j += 1

            for i in range(0, len(tmp)):
                nums[low] = tmp[i]
                low += 1

        divide(0, len(nums) - 1)  
        return self.count  

时间复杂度

相关题目

1.https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/

yan0327 commented 3 years ago

思路: 归并排序的优化,同时在排序完成后cnt值累加,最终输出cnt。 将大数组两两拆分,并计算满足条件的值。 最后获得所需答案

func reversePairs(nums []int) int {
    n := len(nums)
    if n <= 1 {
        return 0
    }

    n1 := append([]int(nil), nums[:n/2]...)
    n2 := append([]int(nil), nums[n/2:]...)
    cnt := reversePairs(n1) + reversePairs(n2) 
    j := 0
    for _, v := range n1 {
        for j < len(n2) && v > 2*n2[j] {
            j++
        }
        cnt += j
    }

    p1, p2 := 0, 0
    for i := range nums {
        if p1 < len(n1) && (p2 == len(n2) || n1[p1] <= n2[p2]) {
            nums[i] = n1[p1]
            p1++
        } else {
            nums[i] = n2[p2]
            p2++
        }
    }
    return cnt
}

时间复杂度:O(nlogn) 空间复杂度:O(n)

biscuit279 commented 3 years ago

思路:构建有序数列,二分

from sortedcontainers import SortedList
class Solution:
    def solve(self, A):
        d = SortedList()
        ans = 0

        for a in A:
            i = d.bisect_right(a * 3)
            ans += len(d) - i
            d.add(a)
        return ans

时间复杂度:O(logn) 空间复杂度:O(n)

QiZhongdd commented 3 years ago
class Solution:
    def solve(self, A):
        ans = 0
        for i in range(len(A)):
            for j in range(i+1,len(A)):
                if A[i] > A[j] * 3: ans += 1
        return ans
shixinlovey1314 commented 3 years ago

Can't AC... I am having issue with the below test case

nums = [3, 4, 3, 1, 0] Your result 7 Expected 5

Base on the constraint, it should be 7 rather than 5

Title:Triple Inversion

Question Reference LeetCode

Solution

Brute Force: Iterate throught the array. For each index i, compare with j (j > i) and count all the j where nums[i] > nums[j] * 3. The time complexity will be O(n^2) which is not good enough.

More stunning solution: use Merge Sort.

The brute force does not work out becase we have to compare each and every pairs, but what if we have the array sorted, then if we have number j, and we found a i that satisfy the constraint, we know that for every k (k > i), it would satisfy the constraint as well. However, if we sort the whole array, we will loose the information of th indices..., what if we could put the array in two parts? left and right, we know that the index in the left will always smaller than the index in the right, and since left part is sorted, once we found a index that satisfy the constraint, we know that all the remaining indices in the left also satisfy the conditon. To do this, we can use merge sort.

Code

int cnt = 0;
void merge(vector<int>& nums, int s, int m, int e) {
    vector<int> l;
    vector<int> r;

    for (int i = s; i <= m; i++)
        l.push_back(nums[i]);
    for (int i = m + 1; i <= e; i++)
        r.push_back(nums[i]);

    l.push_back(INT_MAX);
    r.push_back(INT_MAX);

    int i = 0, j = 0, k = s;
    while (i < l.size() && j < r.size() && k <= e) {
        if (l[i] <= r[j])
            nums[k++] = l[i++];
        else {
            if (l[i] > r[j] * 3) {
                cnt += l.size() - i;
            }
            nums[k++] = r[j++];
        }
    }
}

void mergeSort(vector<int>& nums, int s, int e) {
    if (s >= e)
        return;
    int mid = s + (e - s) / 2;
    mergeSort(nums, s, mid);
    mergeSort(nums, mid + 1, e);
    merge(nums, s, mid, e);
}

int solve(vector<int>& nums) {
    mergeSort(nums, 0, nums.size() - 1);
    return cnt;
}

Complexity

Time Complexity and Explanation

O(nlogn) for merge sort

Space Complexity and Explanation

O(n) used to store the intermidate results for merge.

zhiyuanpeng commented 3 years ago
class Solution:
def maxChunksToSorted(self, nums: List[int]) -> int:

    st = []
    for n in nums:
        if len(st)==0 or st[-1]<=n:
            st.append(n)
        else:
            ma = st[-1]
            while st and st[-1]>n:
                ma = max(ma,st.pop())
            st.append(ma)

    return len(st)
okbug commented 3 years ago

代码

JS

var reversePairs = function(nums) {
    let res = 0;
    for (let i = 0; i < nums.length; i++){
        for (j = i+1; j < nums.length; j++){
            if(nums[i] > nums[j] * 3){
                res++;
            }          
        }
    }

    return res;
};
Victoria011 commented 3 years ago

代码

class Solution:
    def solve(self, nums):
        d = SortedList()
        res = 0
        for i in range(len(nums)):
            tidx = d.bisect_right(d, nums[i]*3)
            res += len(nums) - tidx
            d.add(nums[i])

        return res

复杂度

Time Complexity: O(nlogn)

Space Complexity: O(n)

simonsayshi commented 3 years ago
class Solution {
public:
    int countPrimeSetBits(int l, int r) {
        set<int> primes = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 };
        int cnt = 0;
        for (int i = l; i <= r; i++) {
            int bits = 0;
            for (int n = i; n; n >>= 1)
                bits += n & 1;
            cnt += primes.count(bits);
        }
        return cnt;
    }
};
zhangzz2015 commented 3 years ago

思路

int solve(vector<int>& nums) {

    multiset<int> record;
    int ret =0;   
    for(int i=0; i< nums.size(); i++)
    {

        multiset<int>::iterator it = record.upper_bound(3* nums[i]);
        if(it != record.end())
        {
            ret+= distance(it, record.end());

        }
       record.insert(nums[i]);  
    }
    return ret;
} 

```c++

```c++
int bindarySearch(vector<int>& nums, int left, int right, int val)
{
    while(left <=right)
    {
        int middle = left + (right-left)/2; 
        if(nums[middle]<=val)
        {
            left = middle+1; 
        }
        else
        {
           right = middle-1; 
        }
    }
    return left; 
}
int mergeTwoVec(vector<int>& nums, int left, int middle, int right)
{
    vector<int> tmp(right - left+1);
    int count =0;  
    int left1 = left; 
    int left2 = middle+1; 
    int right1 = middle; 
    int right2 = right;
    int sum =0;
    //cout << "left: " << left << "middle:" << middle << "right:" << right << "\n";  
     while(left1 <=right1 && left2 <=right2)
     {
         if(nums[left1]<= nums[left2])
         {
             tmp[count] = nums[left1]; 
             count++; 
             left1++; 
         }
         else
         {
             // 
             int t = bindarySearch(nums, left1, right1, 3*nums[left2]); 

            sum +=(right1 - t+1);
            //cout << "sum:" << sum << "\n"; 
             tmp[count] = nums[left2]; 
             count++; 
             left2++; 
         }
     }
     while(left1<=right1)
     {
         tmp[count] = nums[left1]; 
         left1++; 
         count++;
     }
     while(left2<=right2)
     {
         tmp[count] = nums[left2]; 
         left2++;
         count++;  
     }
     for(int i=left; i <= right; i++)
     {
         nums[i] = tmp[i-left]; 
     }
     return sum;
}

void mergeSort(vector<int>& nums, int left, int right, int& count)
{
    if(left>=right)
      return; 
    int middle = left + (right - left)/2; 
    mergeSort(nums, left, middle, count); 
    mergeSort(nums, middle+1, right, count); 

    count += mergeTwoVec(nums, left, middle, right);   
}

int solve(vector<int>& nums) {

     int count =0; 
     mergeSort(nums, 0, nums.size()-1, count); 

     return count; 
}
Menglin-l commented 3 years ago

思路:

数组是无序的,需要排序。结合大小关系和位置关系的条件,使用归并排序降低时间复杂度,将数组划分为左右两边,其中i在左边,j在右边,保证了i < j。再加上限制条件nums[i] > nums[j] * 3,从而计算出结果。


代码部分:

class Solution {
    public int reversePairs(int[] nums) {
        if (nums.length < 2) return 0;

        return mergeSort(0, nums.length - 1, nums);
    }

    public int mergeSort(int left, int right, int[] nums) {
        if (left >= right) return 0;

        int mid = left + (right - left) / 2;
        int l = mergeSort(left, mid, nums);
        int r = mergeSort(mid + 1, right, nums);

        return l + r + sort(left, right, mid, nums);
    }

    public int sort(int l, int r, int m, int[] nums) {
        int[] temp = new int[r - l + 1];
        int flag = 0;
        int res = 0;
        // 每一次堆排之前,左右分割出来的i一定小于j,此时只需要判断第二条件是否满足即可统计该次排序得出的翻转对数量
        int i = l;
        int j = m + 1;
        // 计算翻转对
        while (i <= m && j <= r) {
            if (nums[i] > (long) nums[j] * 3) {
                // 统计出i一共可以满足几个翻转对
                res += m - i + 1;
                j ++;
            } else {
                i ++;
            }
        }

        i = l;
        j = m + 1;

        // 进行排序

        while (i <= m && j <= r){
            if (nums[i] < nums[j]) {
                temp[flag ++] = nums[i ++];
            } else {
                temp[flag ++] = nums[j ++];
            }
        }
        while (i <= m){
            temp[flag ++] = nums[i ++];
        }

        while (j <= r){
            temp[flag ++] = nums[j ++];
        }

        for (int k = 0; k < temp.length; k ++){
            nums[l + k] = temp[k];
        }

        return res;

    }
}

复杂度:

Time: O(NlogN)

Space: O(N)

james20141606 commented 3 years ago

Day 39: 757. Triple Inversion (binary search, balanced binary tree, divide and conquer, merge sort)

ti, tj = start, mid + 1
while ti <= mid and tj <= end:
    if nums[ti] <=  3 * nums[tj]:
        ti += 1
    else:
        self.cnt += mid - ti + 1
        tj += 1
#TLE!
class Solution:
    def solve(self, nums):
        res = 0
        for i in range(len(nums)):
            for j in range(i, len(nums)):
                if nums[i] > nums[j] * 3:
                    res += 1
        return res

#binary search 

class Solution:
    def solve(self, A):
        d = []
        ans = 0

        for a in A:
            i = bisect.bisect_right(d, a * 3)
            ans += len(d) - i
            bisect.insort(d, a)

#binary search! use balanced binary tree

from sortedcontainers import SortedList
class Solution:
    def solve(self, A):
        d = SortedList()
        ans = 0

        for a in A:
            i = d.bisect_right(a * 3)
            ans += len(d) - i
            d.add(a)
            #print (d, a, i)
        return ans

#divide and conquer, merge sort idea.

class Solution:
    def solve(self, nums) -> int:
        self.cnt = 0
        def merge(nums, start, mid, end, temp):
            i, j = start, mid + 1
            while i <= mid and j <= end:
                if nums[i] <=  nums[j]:
                    temp.append(nums[i])
                    i += 1
                else:
                    temp.append(nums[j])
                    j += 1
            # 防住
            # 这里代码开始
            ti, tj = start, mid + 1
            while ti <= mid and tj <= end:
                if nums[ti] <=  3 * nums[tj]:
                    ti += 1
                else:
                    self.cnt += mid - ti + 1
                    tj += 1
            # 这里代码结束
            while i <= mid:
                temp.append(nums[i])
                i += 1
            while j <= end:
                temp.append(nums[j])
                j += 1
            for i in range(len(temp)):
                nums[start + i] = temp[i]
            temp.clear()

        def mergeSort(nums, start, end, temp):
            if start >= end: return
            mid = (start + end) >> 1
            mergeSort(nums, start, mid, temp)
            mergeSort(nums, mid + 1, end, temp)
            merge(nums, start, mid,  end, temp)
        mergeSort(nums, 0, len(nums) - 1, [])
        return self.cnt
jsu-arch commented 3 years ago

思路

二分法

构造有序数列,使用二分法找到插入点,并且将数插入数组中,使得插入的数组仍然有序。


    def solve(self, nums):
        d = SortedList()
        ans = 0

        for num in nums:
            i = d.bisect_right(num * 3)
            ans += len(d) - i
            d.add(num)
        return ans

Complexity

Time Complexity: O(nlogn) Space Complexity: O(n)

QiZhongdd commented 3 years ago

function merge(arr1,arr2){ let temp=[]; let i=0,j=0; while(i<arr1.length&&j<arr2.length){ if(arr1[i]<arr2[j]){ temp.push(arr1[i]); i++ }else{ temp.push(arr2[j]) if(arr1[i]>arr2[j]*3){ ans++ } j++ } }

while(i<arr1.length){ temp.push(arr1[i]); i++ } while(j<arr2.length){ temp.push(arr2[j]); j++

} return temp }

taojin1992 commented 3 years ago

Code: 493. Reverse Pairs

class Solution {

    // [2147483647,2147483647,2147483647,2147483647,2147483647,2147483647]
    // 0
    // Time: O(n^2)
    // Space: O(1)
    public int reversePairs1(int[] nums) {
        int count = 0;
        for (int j = 0; j < nums.length; j++) {
            for (int i = 0; i < j; i++) {
                if (nums[i] -  nums[j] > nums[j]) {
                    count++;
                }
            }
        }
        return count;
    }

    // optimized
    /*
    Plan:
    use a binary search tree to track (count of values <= current val, left child, right child)
    search long type (2*target + 1), to avoid overflow
    */

    // The worst time can be O(n^2), it is better to use balanced tree (AVL, or red-black)
    // on average O(nlogn)
    class Node {
        long val;
        int count;
        Node left;
        Node right;

        Node(long val, Node left, Node right) {
            this.val = val;
            this.count = 1;
            this.left = left;
            this.right = right;
        }
    }

    // return the count of numbers <
    private int search(Node root, long target) {
        if (root == null) return 0;
        if (root.val > target) {
            return root.count + search(root.left, target);
        } else if (root.val < target) {
            return search(root.right, target);
        } else {
            return root.count;
        }
    }

    private Node insert(Node root, int target) {
        if (root == null) {
            return new Node(target, null, null);
        } else if (root.val == target) {
            root.count++;
        } else if (root.val > target) {
            root.left = insert(root.left, target);
        } else {
            root.count += 1;
            root.right = insert(root.right, target);
        }
        return root;
    }

    public int reversePairs(int[] nums) {
        int numOfPairs = 0;
        Node root = null;

        for (int num : nums) {
            numOfPairs += search(root, (long) (num * 2 + 1));
            root = insert(root, num);
        }
        return numOfPairs;
    }
}
falconruo commented 3 years ago

思路: 归并法

复杂度:

代码:


class Solution {
public:
    int reversePairs(vector<int>& nums) {
        return mergeSort(nums, 0, nums.size() - 1);
    }
    int mergeSort(vector<int>& nums, int left, int right) {
        if (left >= right) return 0;
        int mid = left + (right - left) / 2;
        int res = mergeSort(nums, left, mid) + mergeSort(nums, mid + 1, right);
        for (int i = left, j = mid + 1; i <= mid; ++i) {
            while (j <= right && nums[i] / 2.0 > nums[j]) ++j;
            res += j - (mid + 1);
        }
        sort(nums.begin() + left, nums.begin() + right + 1);
        return res;
    }
};
chen445 commented 3 years ago

代码

class Solution:
    def countPrimeSetBits(self, left: int, right: int) -> int:
        result=0
        for num in range(left,right+1):
            if self.to_binary_bit(num):
                result+=1
        return result

    def to_binary_bit(self,num):
        prime=set([2,3,5,7,11,13,17,19,23])
        count=0
        while num !=0:
            if num%2 ==1:
                count+=1
            num=num//2
        if count in prime:
            return True
        else:
            return False

复杂度

Time: O(nlogn)

Space: O(1)

florenzliu commented 3 years ago

Explanation

Python

class Solution:
    def solve(self, nums):
        def mergeSort(start, end, temp):
            if start < end:
                mid = start + (end-start)//2
                mergeSort(start, mid, temp)
                mergeSort(mid+1, end, temp)
                merge(start, mid, end, temp)

        def merge(start, mid, end, temp):
            nonlocal count
            i, j = start, mid+1
            while i <= mid and j <= end:
                if nums[i] <= nums[j]:
                    temp.append(nums[i])
                    i += 1
                else:
                    temp.append(nums[j])
                    j += 1

            ti, tj = start, mid+1
            while ti <= mid and tj <= end:
                if nums[ti] <= nums[tj] * 3:
                    ti += 1
                else:
                    count += mid - ti + 1
                    tj += 1

            while i <= mid:
                temp.append(nums[i])
                i += 1
            while j <= end:
                temp.append(nums[j])
                j += 1
            for i in range(len(temp)):
                nums[start+i] = temp[i]
            temp.clear()

        count = 0
        mergeSort(0, len(nums)-1, [])
        return count

Complexity:

15691894985 commented 3 years ago

【day 39】762.Number Stream to Intervals

https://binarysearch.com/problems/Triple-Inversion

思路:讲义中有讲到这题,观察需要自己构造有序序列。反向思考,对于nums中的每一项num,找前面出现过的大于num * 3的数

import bisect
def solve(self,A):
    d = SortedList()
    ans = 0
    for a in A:
        i = bisect.bisect_right(d, a * 3) #有序序列的查找,查找a*3在有序序列中的位置
        ans += len(d) - i #在i位置之后的数满足题目要求
        bisect.insort(d, a) #有序序列的插入
    return ans

# 1141 milliseconds #
class Solution:
      def solve(self, A):
        d = SortedList()
        ans = 0

        for a in A:
            i = d.bisect_right(a * 3)
            ans += len(d) - i
            d.add(a)
        return ans  
  #502 milliseconds#

复杂度:

时间复杂度:O(nlog n) 二分中找到插入点的时间复杂度为O(logn),但由于数组项后移动的时间复杂度为O(n),可以采用平衡二叉树来使插入时间减少稳定在O(logn) Python 可使用 SortedList 来实现, Java 可用 TreeMap 代替

空间复杂度:O(n)

leolisgit commented 3 years ago

思路

类似于 315. Count of Smaller Numbers After Self 求有条件的逆序对。有两种解法,

  1. merge sort,在merge的过程中可以求得满足条件的逆序对。
  2. 二分 + 插入排序。

代码

class Solution {
    public int main(int[] nums) {
        List<Integer> list = new ArrayList<>();
        int ret= 0;
        for (int n : nums) {
            int idnex = search(list, n * 3);
            ret += list.size() - idnex;
            list.add(search(list, n), n);
        }
        return ret;
    }

    public int search(List<Integer> list, int n) {
        int start = 0, end = list.size() - 1;
        while (start <= end) {
            int mid = (start + end) >>> 1;
            if (list.get(mid) <= n) {
                start = mid + 1;
            } else {
                end = mid - 1;
            }
        }
        return start;
    }
}

复杂度

时间:O(nlogn)
空间:O(n)

ZoharZhu commented 3 years ago

思路

类似于 315. Count of Smaller Numbers After Self 求有条件的逆序对。两种解法: merge sort,在merge的过程中可以求得满足条件的逆序对。 二分 + 插入排序。

代码

class Solution {
    public int main(int[] nums) {
        List<Integer> list = new ArrayList<>();
        int ret= 0;
        for (int n : nums) {
            int idnex = search(list, n * 3);
            ret += list.size() - idnex;
            list.add(search(list, n), n);
        }
        return ret;
    }

    public int search(List<Integer> list, int n) {
        int start = 0, end = list.size() - 1;
        while (start <= end) {
            int mid = (start + end) >>> 1;
            if (list.get(mid) <= n) {
                start = mid + 1;
            } else {
                end = mid - 1;
            }
        }
        return start;
    }
}

复杂度

ysy0707 commented 3 years ago

思路:二分

class Solution {
    public int solve(int[] nums) {
        int res = 0;
        List<Integer> sortedNums = new ArrayList<>();
        for(int i = 0; i < nums.length; i++){
            int leftBorder = findLeftBorder(sortedNums, nums[i] * 3);
            res += i - leftBorder;
            int insertIndex = findLeftBorder(sortedNums, nums[i]);
            sortedNums.add(insertIndex, nums[i]);
        }
        return res;

    }
    private int findLeftBorder(List<Integer> sortedNums, int target){
        int left = 0, right = sortedNums.size() - 1;
        while(left <= right){
            int mid = (left + right) / 2;
            if(sortedNums.get(mid) <= target){
                left = mid + 1;
            }else{
                right = mid - 1;
            }
        }
        return left;
    }
}

时间复杂度:O(NlogN) 空间复杂度:O(N)

kennyxcao commented 3 years ago

Triple Inversion

Problem Source

Intuition

Code

class Solution {
  solve(nums) {
    const sorted = [];
    let count = 0
    for (const num of nums) {
      const idx = this.findFirstLarger(sorted, num * 3);
      count += sorted.length - idx;
      sorted.splice(this.findFirstLarger(sorted, num), 0, num);
    }
    return count;
  }

  findFirstLarger(arr, target) {
    let start = 0;
    let end = arr.length;
    while (start < end) {
      const mid = start + ~~((end - start) / 2);
      if (arr[mid] > target) {
        end = mid;
      } else {
        start = mid + 1;
      }
    }
    return start;
  }
}

Complexity Analysis

Wu-zonglin commented 3 years ago

思路

对于nums中的每一项num,找前面出现过的大于num * 3的数

import bisect
def solve(self,nums):
    d = SortedList()
    ans = 0
    for a in nums:
        i = bisect.bisect_right(d, a * 3) #查找a*3在有序序列中的位置
        ans += len(d) - i 
        bisect.insort(d, a) #在有序序列中的插入
    return ans
chaggle commented 3 years ago

title: "Day 39 762.Number Stream to Intervals" date: 2021-10-18T16:30:01+08:00 tags: ["Leetcode", "c++", "Binary Search"] categories: ["91-day-algorithm"] draft: true


762.Number Stream to Intervals

题目

Given a list of integers nums, return the number of pairs i < j such that nums[i] > nums[j] * 3.

Constraints

n ≤ 100,000 where n is the length of nums
Example 1
Input
nums = [7, 1, 2]
Output
2
Explanation
We have the pairs (7, 1) and (7, 2)

题目思路

  • 1、构造逆序对,然后返回逆序对的数量,使用归并排序比二分法更加合适,找出每个子区间中一项大于当前num * 3的值
void merge(vector<int> &nums, int i, int mid, int j) 
{

    vector<int> ans(j - i + 1);
    int l = i, r = mid + 1;
    int cnt = 0;

    while(l <= mid && r <= j) 
    {
        if(nums[l] <= nums[r]) 
        {
            ans[cnt] = nums[l];
            l++;
        } 
        else 
        {
            ans[cnt] = nums[r];
            r++;
        }
        cnt++;
    }

    while(l <= mid) ans[cnt++] = nums[l++];
    while(r <= j) ans[cnt++] = nums[r++];

    cnt = 0;
    while(i <= j) nums[i++] = ans[cnt++];
    }
}

int mergeSort(vector<int> &nums, int l, int r) 
{
    if(r <= l) return 0;
    int ans = 0;
    int mid = (l + r) / 2;
    ans += mergeSort(nums, l, mid);
    ans += mergeSort(nums, mid + 1, r);

    int p = l;
    int q = mid + 1;
    while(p <= mid && q <= r) 
    {
        if(nums[p] > nums[q] * 3) 
        {
            ans += (mid - p + 1);
            q++;
        } 
        else p++;
    }
    merge(nums, l, mid, r);
    return ans;
}

int solve(vector<int> &nums) 
{
    int ans = mergeSort(nums, 0, nums.size() - 1);
    return ans;
}

复杂度

asterqian commented 3 years ago

思路

利用merge sort计算逆序数

代码

class Solution {
public:
    int reversePairs(vector<int>& nums) {
        if (nums.size() == 0) return 0;
        // merge sort on the whole vector
        return mergeSort(nums, 0, nums.size() - 1);
    }

    int mergeSort(vector<int>& nums, int l, int r) {
        if (l == r) return 0;
        int mid = l + (r - l) / 2;
        // number of ans from left half and right half
        int res = mergeSort(nums, l, mid) + mergeSort(nums, mid + 1, r);

        // split in half
        int i = l;
        int j = mid + 1;
        while (i <= mid) {
            // j is not out-of-bound and meets the requirement
            while (j <= r && (long long) nums[i] > (long long) nums[j] * 3) j++;
            // add the number of values that meet the requirement and after it
            res += j - mid - 1;
            ++i;
        }
        sort(nums.begin() + l, nums.begin() + r + 1);
        return res;
    }
};

Time Complexity: O(NlogN)

Space Complexity: O(N)

RonghuanYou commented 3 years ago
class Solution:
    def solve(self, nums):
        self.cnt = 0

        def merge(nums, left, mid, right, temp):
            i, j = left, mid + 1
            while i <= mid and j <= right:
                if nums[i] <= nums[j]:
                    temp.append(nums[i])
                    i += 1
                else:
                    temp.append(nums[j])
                    j += 1

            while i <= mid:
                temp.append(nums[i])
                i += 1

            while j <= right:
                temp.append(nums[j])
                j += 1

            ti, tj = left, mid + 1
            while ti <= mid and tj <= right:
                if nums[ti] <= 3 * nums[tj]:
                    ti += 1
                else:
                    self.cnt += mid - ti + 1
                    tj += 1

            for i in range(len(temp)):
                nums[left + i] = temp[i]
            temp.clear()

        def merge_sort(nums, left, right, temp):
            if left >= right:
                return

            mid = (left + right) // 2
            merge_sort(nums, left, mid, temp)
            merge_sort(nums, mid + 1, right, temp)
            merge(nums, left, mid, right, temp)

        merge_sort(nums, 0, len(nums) - 1, [])
        return self.cnt
Francis-xsc commented 3 years ago

思路

二分,抄下别人的

代码


int solve(vector<int>& nums) {
    map<int, int> dict;
    int res = 0;
    for (auto& num : nums)
    {
        auto it = dict.upper_bound(3*num); // 找到第1个满足要求的数key1, 那哈希表中排在key1后面的数(比key1更大)也全满足 > 3*num
        if (it != dict.end())
        {
            for (auto it1 = it; it1 != dict.end(); it1++)
                res += it1->second;
        }        

        if (dict.count(num) > 0)
            dict[num]++; 
        else dict[num] = 1;      
    }
    return res;
}

复杂度分析

Cartie-ZhouMo commented 3 years ago

思路

自己构造有序数组,遍历原数组找到在num前且大于num*3的数的个数,并将num加入有序数组。

代码

class Solution:
    def solve(self, nums):
        arr = SortedList()
        ans = 0
        for n in nums:
            i = arr.bisect_right(n)
            ans += len(arr) - i
            arr.add(n)
        return ans

复杂度

learning-go123 commented 3 years ago

思路

代码

Go Code:


func reversePairs(nums []int) int {
    var res int
    mergeSort(nums, 0, len(nums)-1, &res)
    return res
}

func mergeSort(nums []int, left, right int, res *int) {
    if left >= right {
        return
    }
    mid := (right-left)/2 + left
    mergeSort(nums, left, mid, res)
    mergeSort(nums, mid+1, right, res)
    merge(nums, left, mid, right, res)
}

func merge(nums []int, left, mid, right int, res *int) {
    newNums := make([]int, right-left+1)
    index, i, j := 0, left, mid+1
    for i <= mid && j <= right {
        if nums[i] > 2*nums[j] {
            *res += mid - i + 1
            j++
        } else {
            i++
        }
    }

    i, j = left, mid+1
    for i <= mid && j <= right {
        if nums[i] < nums[j] {
            newNums[index] = nums[i]
            i++
        } else {
            newNums[index] = nums[j]
            j++
        }
        index++
    }

    // 多余的数据尾部插入
    for i <= mid {
        newNums[index] = nums[i]
        i++
        index++
    }
    for j <= right {
        newNums[index] = nums[j]
        j++
        index++
    }

    for _, num := range newNums {
        nums[left] = num
        left++
    }
}

复杂度分析

令 n 为数组长度。

AstrKing commented 3 years ago

思路

二分法

代码

class Solution:
    def solve(self, A):
        d = []
        ans = 0

        for a in A:
            i = bisect.bisect_right(d, a * 3)
            ans += len(d) - i
            bisect.insort(d, a)

时间复杂度:O(logn)

空间复杂度:O(n)

muimi commented 3 years ago

思路

借助归并排序,在归并排序的过程中,利用↓的特点进行统计。

归并排序的特点:合并之前,左分支和右分支就已经是有序的了。

// 伪代码
mergeSort(...) {
  mergeSort(leftPart);
  mergeSort(rightPart);
  // 递归执行到这里,leftPart和rightPart都已经sorted
  countPairs(...);
  merge(leftPart, rightPart);
}

代码

class Solution {
  public int reversePairs(int[] nums) {
    return mergeSort(nums, 0, nums.length - 1);
  }
  private int mergeSort(int[] nums, int left, int right){
    if (left >= right) return 0;
    int middle = left + (right - left) / 2;
    int res = mergeSort(nums, left, middle) + mergeSort(nums, middle + 1, right);
    for(int leftIndex = left, rightIndex = middle + 1; leftIndex <= middle; leftIndex++) {
        while (rightIndex <= right && nums[leftIndex] / 3.0 > nums[rightIndex]) rightIndex++;
        res += rightIndex - (middle + 1);
    }
        // 合并左右分支,相当于进行了依次排序
    Arrays.sort(nums, left, right + 1);
    return res;
  }
}

复杂度

peteruixi commented 3 years ago

思路

实现一个二分查找法: 找到保持有序情况下 最右的插入位置 实现逻辑为, 建立一个列表, 成为我们的查找区间, 然后便利输入的列表. 查找 3遍历值num , 找到会是插入下标, 此时满足条件 i<j 且 nums[i]>nums[j]3 增加count: len(temp) - 刚找到的下标 最后找到插入 num的位置,并插入

代码

class Solution:
    def solve(self, nums):
        def binarySearch(temp, target):
            left = 0
            right = len(temp)
            while left<right:
                mid = (right+left)//2
                if temp[mid]<= target:
                    left = mid+1
                else:
                    right = mid
            return left
        count = 0
        temp = []
        for num in nums: 
            smaller_count = binarySearch(temp,num*3)
            print(temp,smaller_count)
            count += len(temp) - smaller_count
            idx  = binarySearch(temp,num)
            temp.insert(idx,num)
        return count

复杂度分析

Richard-LYF commented 3 years ago

class Solution: def solve(self, nums): d = [] ans = 0

    for a in A:
        i = bisect.bisect_right(d, a * 3)
        ans += len(d) - i
        bisect.insort(d, a)

        # logn n
sxr000511 commented 3 years ago

class Solution { public int reversePairs(int[] nums) { return mergeSort(nums, 0, nums.length - 1); } private int mergeSort(int[] nums, int left, int right){ if (left >= right) return 0; int middle = left + (right - left) / 2; int res = mergeSort(nums, left, middle) + mergeSort(nums, middle + 1, right); for(int leftIndex = left, rightIndex = middle + 1; leftIndex <= middle; leftIndex++) { while (rightIndex <= right && nums[leftIndex] / 3.0 > nums[rightIndex]) rightIndex++; res += rightIndex - (middle + 1); } // 合并左右分支,相当于进行了依次排序 Arrays.sort(nums, left, right + 1); return res; } }

shawncvv commented 3 years ago

思路

二分法

代码

Python Code

class Solution:
    def solve(self, nums) -> int:
        self.cnt = 0
        def merge(nums, start, mid, end, temp):
            i, j = start, mid + 1
            while i <= mid and j <= end:
                if nums[i] <=  nums[j]:
                    temp.append(nums[i])
                    i += 1
                else:
                    temp.append(nums[j])
                    j += 1
            # 防住
            # 这里代码开始
            ti, tj = start, mid + 1
            while ti <= mid and tj <= end:
                if nums[ti] <=  3 * nums[tj]:
                    ti += 1
                else:
                    self.cnt += mid - ti + 1
                    tj += 1
            # 这里代码结束
            while i <= mid:
                temp.append(nums[i])
                i += 1
            while j <= end:
                temp.append(nums[j])
                j += 1
            for i in range(len(temp)):
                nums[start + i] = temp[i]
            temp.clear()

        def mergeSort(nums, start, end, temp):
            if start >= end: return
            mid = (start + end) >> 1
            mergeSort(nums, start, mid, temp)
            mergeSort(nums, mid + 1, end, temp)
            merge(nums, start, mid,  end, temp)
        mergeSort(nums, 0, len(nums) - 1, [])
        return self.cnt

复杂度

freedom0123 commented 3 years ago
class Solution {
    public int lowbit(int x){
        return x&-x;
    }
    public boolean judget(int n ){
        if(n<2){
            return false;
        }
        for(int i =2;i<=n/i;i++){
            if(n%i==0){
                return false;
            }
        }
        return true;
    }
    public int countPrimeSetBits(int left, int right) {
        int ans  = 0;
        for(int i  = left;i<=right;i++){
            int tem  = 0;
            int x  = i;
            while(x!=0){
                x-=lowbit(x);
                tem++;
            }
            if(judget(tem)){
                ans++;
            }
        }
        return ans;

    }
}
JianXinyu commented 3 years ago

思路

构造有序序列.

参考题解 在把一个element插入sorted array时, 我们想得到它的位置. 用STLset的问题在于, 为了得到位置, 还得再subtract iterators and this operation is O(n). 可以自定义一个indexed_set, 只有O(logn).

Code

using namespace __gnu_pbds;
typedef tree<pair<int, int>, null_type, less<pair<int, int>>, rb_tree_tag,
             tree_order_statistics_node_update>
    indexed_set;

int solve(vector<int>& nums) {
    indexed_set sett;
    int ans = 0;
    for (int i = nums.size() - 1; i >= 0; i--) {
        ans += sett.order_of_key(make_pair(nums[i], i));
        sett.insert(make_pair(3 * nums[i], i));
    }

    return ans;
}
flame0409 commented 3 years ago

代码

class Solution {
  public int reversePairs(int[] nums) {
    return mergeSort(nums, 0, nums.length - 1);
  }
  private int mergeSort(int[] nums, int left, int right){
    if (left >= right) return 0;
    int middle = left + (right - left) / 2;
    int res = mergeSort(nums, left, middle) + mergeSort(nums, middle + 1, right);
    for(int leftIndex = left, rightIndex = middle + 1; leftIndex <= middle; leftIndex++) {
        while (rightIndex <= right && nums[leftIndex] / 3.0 > nums[rightIndex]) rightIndex++;
        res += rightIndex - (middle + 1);
    }
        // 合并左右分支,相当于进行了依次排序
    Arrays.sort(nums, left, right + 1);
    return res;
  }
}

复杂度

jinmenghan commented 3 years ago

代码

Java Code:


class Solution {
    public int main(int[] nums) {
        List<Integer> list = new ArrayList<>();
        int ret= 0;
        for (int n : nums) {
            int idnex = search(list, n * 3);
            ret += list.size() - idnex;
            list.add(search(list, n), n);
        }
        return ret;
    }

    public int search(List<Integer> list, int n) {
        int start = 0, end = list.size() - 1;
        while (start <= end) {
            int mid = (start + end) >>> 1;
            if (list.get(mid) <= n) {
                start = mid + 1;
            } else {
                end = mid - 1;
            }
        }
        return start;
    }
}

复杂度分析

令 n 为数组长度。

xjlgod commented 3 years ago
class Solution {
    private int count = 0;

    public int reversePairs(int[] nums) {
        if (nums == null || nums.length < 2) {
            return 0;
        }
        count = 0;  
        mergeSort(nums, 0, nums.length - 1);      
        return count;
    } 

    private void mergeSort(int[] nums, int start, int end) {
        // 一个时不用划分
        if (start == end) {
            return;
        }
        int mid = start + (end - start) / 2;
        mergeSort(nums, start, mid);
        mergeSort(nums, mid + 1, end);
        // 开始合并
        int i = start;
        int j = mid + 1;
        // 开始统计翻转对
        while (i <= mid && j <= end) {
            if ((long) nums[i] > 2 * (long) nums[j]) {
                count += mid - i + 1;
                j++;
            } else {
                i++;
            }
        }
        // 统计完之后合并
        int[] tempArr = new int[end - start + 1];
        i = start;
        j = mid + 1;
        int index = 0;
        while (i <= mid && j <= end) {
            tempArr[index++] = nums[i] < nums[j] ? nums[i++] : nums[j++]; 
        }
        while (i <= mid) {
            tempArr[index++] = nums[i++];
        }
        while (j <= end) {
            tempArr[index++] = nums[j++];
        }
        for (i = 0, j = start; j <= end; i++, j++) {
            nums[j] = tempArr[i];
        }
    }

}
nerrolk commented 3 years ago

先打个卡

int solve(vector<int>& nums) {
    map<int, int> dict;
    int res = 0;
    for (auto& num : nums)
    {
        auto it = dict.upper_bound(3*num); // 找到第1个满足要求的数key1, 那哈希表中排在key1后面的数(比key1更大)也全满足 > 3*num
        if (it != dict.end())
        {
            for (auto it1 = it; it1 != dict.end(); it1++)
                res += it1->second;
        }        

        if (dict.count(num) > 0)
            dict[num]++; 
        else dict[num] = 1;      
    }
    return res;
}
HouHao1998 commented 3 years ago

思想

代码

 class Solution {
        public int solve(int[] nums) {
            if (nums.length == 0) return 0;
            int res = 0;
            TreeMap<Integer, Integer> map = new TreeMap<>();
            map.put(nums[0], 1);
            for (int i = 1; i < nums.length; i++) {
                Map<Integer, Integer> candidates = map.tailMap(3 * nums[i], false);
                for (Map.Entry<Integer, Integer> entry: candidates.entrySet()) {
                    res += entry.getValue();
                }
                map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
            }
            return res;
        }
    }
Lydia61 commented 3 years ago

Number Stream to Intervals

思路

二分法

代码

class Solution:
    def solve(self, nums) -> int:
        self.cnt = 0
        def merge(nums, start, mid, end, temp):
            i, j = start, mid + 1
            while i <= mid and j <= end:
                if nums[i] <=  nums[j]:
                    temp.append(nums[i])
                    i += 1
                else:
                    temp.append(nums[j])
                    j += 1
            # 防住
            # 这里代码开始
            ti, tj = start, mid + 1
            while ti <= mid and tj <= end:
                if nums[ti] <=  3 * nums[tj]:
                    ti += 1
                else:
                    self.cnt += mid - ti + 1
                    tj += 1
            # 这里代码结束
            while i <= mid:
                temp.append(nums[i])
                i += 1
            while j <= end:
                temp.append(nums[j])
                j += 1
            for i in range(len(temp)):
                nums[start + i] = temp[i]
            temp.clear()

        def mergeSort(nums, start, end, temp):
            if start >= end: return
            mid = (start + end) >> 1
            mergeSort(nums, start, mid, temp)
            mergeSort(nums, mid + 1, end, temp)
            merge(nums, start, mid,  end, temp)
        mergeSort(nums, 0, len(nums) - 1, [])
        return self.cnt

复杂度分析

Auto-SK commented 3 years ago

思路

归并排序。

程序

class Solution:
    def solve(self, nums):
        def merge_sort(l, r):
            # 终止条件
            if l >= r:
                return 0
            # 递归划分
            m = ((r - l) >> 1) + l
            res = merge_sort(l, m) + merge_sort(m + 1, r)
            # 合并阶段
            i, j = l, m + 1
            t = l
            tmp[l:r+1] = nums[l:r+1]
            for k in range(l, r + 1):
                if i >= m + 1:
                    nums[k] = tmp[j]
                    j += 1
                elif j >= r + 1 or tmp[i] <= tmp[j]:
                    nums[k] = tmp[i]
                    i += 1
                else:
                    # 开始,去除不符合条件的 tmp[t] <= 3 * tmp[j]
                    while t <= m and tmp[t] <= 3 * tmp[j]:
                        t += 1
                    # 结束
                    res += m - t + 1
                    nums[k] = tmp[j]
                    j += 1
            return res
        tmp = [0] * len(nums)
        return merge_sort(0, len(nums) - 1)

复杂度

iambigchen commented 3 years ago

思路

二分(打卡)

代码

class Solution:
    def solve(self, A):
        d = SortedList()
        ans = 0

        for a in A:
            i = d.bisect_right(a * 3)
            ans += len(d) - i
            d.add(a)
        return ans
carterrr commented 3 years ago

抄答案

class Solution: def solve(self, nums) -> int: self.cnt = 0 def merge(nums, start, mid, end, temp): i, j = start, mid + 1 while i <= mid and j <= end: if nums[i] <= nums[j]: temp.append(nums[i]) i += 1 else: temp.append(nums[j]) j += 1

防住

        # 这里代码开始
        ti, tj = start, mid + 1
        while ti <= mid and tj <= end:
            if nums[ti] <=  3 * nums[tj]:
                ti += 1
            else:
                self.cnt += mid - ti + 1
                tj += 1
        # 这里代码结束
        while i <= mid:
            temp.append(nums[i])
            i += 1
        while j <= end:
            temp.append(nums[j])
            j += 1
        for i in range(len(temp)):
            nums[start + i] = temp[i]
        temp.clear()

    def mergeSort(nums, start, end, temp):
        if start >= end: return
        mid = (start + end) >> 1
        mergeSort(nums, start, mid, temp)
        mergeSort(nums, mid + 1, end, temp)
        merge(nums, start, mid,  end, temp)
    mergeSort(nums, 0, len(nums) - 1, [])
    return self.cnt