首页 > 其他分享 >[leetcode 3171] 解法列表

[leetcode 3171] 解法列表

时间:2024-06-03 22:23:31浏览次数:8  
标签:return nums int public ans 3171 st leetcode 解法

  • 线段树解法 + 二分
class Solution {
    public int minimumDifference(int[] nums, int k) {
        this.nums = nums;
        this.n = nums.length;
        return check(k);
    }

    public static void main(String[] args) {
        Solution solution = new Solution();
        int ans = solution.minimumDifference(new int[]{
                9,71,98,44,30
        }, 26);
        System.out.println(ans);
    }

    public int check(int k) {
        Seg seg = build(0, n - 1);
        int ans = Integer.MAX_VALUE;
        for (int i = 0; i < n; i++) {
            int l = i;
            int r = n - 1;

            while (l <= r) {
                int mid = (l + r) / 2;
                int val = seg.query(i, mid);
                ans = Math.min(ans, Math.abs(val - k));

                if (val < k) {
s                    // 往大的方向靠
                    // 也就是右端点要向靠近l
                    r = mid - 1;
                } else if (val == k) {
                    return 0;
                } else {
                    // > k, 往小的方向靠
                    // 也就是右端点要靠近r
                    l = mid + 1;
                }
            }
        }
        return ans;
    }


    class Seg {
        int l, r;
        Seg left, right;
        int value;

        public Seg(int l, int r) {
            this.l = l;
            this.r = r;
            left = null;
            right = null;
        }

        public int query(int l, int r) {
            if (this.l > r || this.r < l) {
                return Integer.MAX_VALUE;
            }
            if (l <= this.l && this.r <= r) {
                return this.value;
            }
            return this.left.query(l, r) & this.right.query(l, r);
        }
    }

    int[] nums;
    int n;

    public Seg build(int l, int r) {
        if (l == r) {
            Seg seg = new Seg(l, l);
            seg.value = nums[l];
            return seg;
        }
        Seg left = build(l, (l + r) / 2);
        Seg right = build((l + r) / 2 + 1, r);
        Seg seg = new Seg(l, r);
        seg.left = left;
        seg.right = right;
        seg.value = left.value & right.value;
        return seg;
    }
}
  • 双指针解法
class Solution {
  public boolean hasMask(int num, int i) {
    return (num & (1 << i)) != 0;
  }

  public static void main(String[] args) {
    Solution solution = new Solution();
    int ans = solution.minimumDifference(new int[]{
        1, 10, 6
    }, 7);
    System.out.println(ans);
  }

  public int minimumDifference(int[] nums, int k) {
    // dp[i][b] 表示前i个数第b位为0个数
    int n = nums.length;
    int[][] dp = new int[n][32];
    for (int i = 0; i < n; i++) {
      for (int b = 31; b >= 0; b--) {
        if (i == 0) {
          dp[i][b] = hasMask(nums[i], b) ? 0 : 1;
          continue;
        }
        dp[i][b] = dp[i - 1][b] + (hasMask(nums[i], b) ? 0 : 1);
      }
    }

    //
    int j = -1;
    int ans = Integer.MAX_VALUE;
    int x = Integer.MAX_VALUE;
    while (j < n && x > k) {
      j++;
      if (j == n) {
        break;
      }
      x = x & nums[j];
      ans = Math.min(ans, Math.abs(x - k));
    }
    // [0..j] 其中a0...aj是小于等于k的。
    // [i..j]开始重新计算
    for (int i = 1; i < nums.length && j < n; i++) {
      if (j < i) {
        j = i;
        x = nums[i];
      } else {
        int last = nums[i - 1];
        // 考虑哪些为0的位,是否会改变,为1的位是没有变化的
        // [i-1,j][b]有多少个0
        for (int b = 31; b >= 0; b--) {
          if (!hasMask(x, b) && !hasMask(last, b) && isGreater0(i, j, b, dp)) {
            // need change.
            x = x + (1 << b);
          }
        }
      }
      ans = Math.min(ans, Math.abs(x - k));
      while (j<n && x > k) {
        j++;
        if ( j == n) {
          break;
        }
        x = x & nums[j];
        ans = Math.min(ans, Math.abs(x - k));
      }
    }
    return ans;
  }

  public boolean isGreater0(int i, int j, int b, int[][] dp) {
    int x = dp[i - 1][b];
    int y = dp[j][b];
    int zero = y - x;
    int one = j - i + 1 - zero;
    return zero == 0 && one >=1;
  }
}
  • st 表
class Solution {
    
    static int[] log = new int[100001];// 2^log[i] 表示最接近 i 的 2 的某次方
    static {
        log[0] = -1;
        for (int i = 1; i <= 100000; i++) {
            log[i] = log[i >> 1] + 1;
        }
    }
    int[][] st;

    public int minimumDifference(int[] nums, int k) {
        int n = nums.length;
        st = new int[n][18];
        // st 表预处理
        for (int i = 0; i < n; i++) {
            st[i][0] = nums[i];
        }
        for (int j = 1; j < 18; j++) {
            for (int i = 0; i + (1 << j) - 1 < n; i++) {
                st[i][j] = st[i][j - 1] & st[i + (1 << (j - 1))][j - 1];
            }
        }
        int ans = Integer.MAX_VALUE;
        for (int i = 0; i < n; i++) {
            int l = left(0, i, k), r = right(0, i, k);
            if (l != -1) {
                ans = Math.min(ans, k - l);
            }
            if (r != -1) {
                ans = Math.min(ans, r - k);
            }
        }
        return ans;
    }

    // 固定 r 时, nums[l..r] 按位与值 <= k 的最大值,如果找不到返回 -1
    public int left(int l, int r, int k) {
        int b = r, m, ans = -1;
        while (l <= r) {
            m = (l + r) >> 1;
            int v = query(m, b);// 获取 nums[m..b] 的区间与运算值
            if (v <= k) {
                ans = v;
                l = m + 1;
            } else {
                r = m - 1;
            }
        }
        return ans;
    }

    // 固定 r 时, nums[l..r] 按位与值 >= k 的最小值,如果找不到返回 -1
    public int right(int l, int r, int k) {
        int b = r, m, ans = -1;
        while (l <= r) {
            m = (l + r) >> 1;
            int v = query(m, b);// 获取 nums[m..b] 的区间与运算值
            if (v >= k) {
                ans = v;
                r = m - 1;
            } else {
                l = m + 1;
            }
        }
        return ans;
    }

    // 获取 nums[l..r] 的区间与运算值
    public int query(int l, int r) {
        int lg = log[r - l + 1];
        return st[l][lg] & st[r - (1 << lg) + 1][lg];
    }
       
}

标签:return,nums,int,public,ans,3171,st,leetcode,解法
From: https://www.cnblogs.com/fishcanfly/p/18229802

相关文章

  • leetcode 377. 组合总和 Ⅳ(dp)
    377.组合总和Ⅳ-力扣(LeetCode)dp,跟完全背包反着来,可以当作是爬楼梯来做,相当于每次爬的楼梯数是从数组种选的。1#defineIOstd::ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)2#definebug(x)cout<<#x<<"is"<<x<<endl;3#include<bits/stdc++.h>4usin......
  • Floyd判圈算法 leetcode
    龟兔赛跑/Floyd判圈算法概述判断一个链表是否存在环画图演示两个指针相遇的情况:查找链表中环的首个节点在这里插入图片描述数学公式表示为:(对应力扣142.环形链表II,141.环形链表I)判断一个链表是否存在环龟兔赛跑/Floyd判圈算法转换成判断链表是否存......
  • LeetCode 1168. Optimize Water Distribution in a Village
    原题链接在这里:https://leetcode.com/problems/optimize-water-distribution-in-a-village/description/题目:Thereare n housesinavillage.Wewanttosupplywaterforallthehousesbybuildingwellsandlayingpipes.Foreachhouse i,wecaneitherbuildaw......
  • LeetCode 720. Longest Word in Dictionary
    原题链接在这里:https://leetcode.com/problems/longest-word-in-dictionary/description/题目:Givenanarrayofstrings words representinganEnglishDictionary,return thelongestwordin words thatcanbebuiltonecharacteratatimebyotherwordsin wor......
  • leetcode第263题:丑数
    丑数的因子只能是2,3,5。但是可能有多个2,多个3,多个5.因此需要循环地除以2、3、5.publicclassSolution{publicboolIsUgly(intn){if(n<=0){returnfalse;}int[]factors={2,3,5};for(inti=0;i......
  • leetcode第1281题: 整数的各位积和之差
    publicclassSolution{publicintSubtractProductAndSum(intn){intsum=0;intji=1;while(n>0){intnum=n%10;sum+=num;ji*=num;n/=10;}returnji-sum;......
  • LeetCode 1151. 最少交换次数来组合所有的 1
    1151.最少交换次数来组合所有的1给出一个二进制数组 data,你需要通过交换位置,将数组中 任何位置 上的1组合到一起,并返回所有可能中所需 最少的交换次数。示例1:输入:data=[1,0,1,0,1]输出:1解释:有三种可能的方法可以把所有的1组合在一起:[1,1,1,0,0],交换......
  • LeetCode 1411. Number of Ways to Paint N × 3 Grid
    原题链接在这里:https://leetcode.com/problems/number-of-ways-to-paint-n-3-grid/description/题目:Youhavea grid ofsize nx3 andyouwanttopainteachcellofthegridwithexactlyoneofthethreecolors: Red, Yellow, or Green whilemakingsuretha......
  • leetcode 60 排列序列
    排列序列已解答困难相关标签相关企业给出集合[1,2,3,...,n],其所有元素共有n!种排列。按大小顺序列出所有排列情况,并一一标记,当n=3时,所有排列如下:"123""132""213""231""312""321"给定n和k,返回第k个排列。示例1:输入:n=3,k=3输出:"213"示......
  • Leetcode 3171. Find Subarray With Bitwise AND Closest to K
    Leetcode3171.FindSubarrayWithBitwiseANDClosesttoK1.解题思路2.代码实现题目链接:3171.FindSubarrayWithBitwiseANDClosesttoK1.解题思路这道题坦率地说让我感觉很挫败,又一次没有自力搞定,是看了大佬们的答案才搞定的……知道比没有搞定更难受的......