力扣刷题篇之每日一题(2023年11月ing)

持续更新ing  11.14

前言

想着每天都要刷每日一题的,但每次刷过了也没啥留下的,之后也容易忘,不如记录下来,一些知识,解题技巧,有趣的,碎碎念的。。。工作日就每日都更新,周末的题可能会留到周一更新。

每日一题

1

第一天就难度升级

力扣刷题篇之每日一题(2023年11月ing)_第1张图片

 力扣刷题篇之每日一题(2023年11月ing)_第2张图片

力扣刷题篇之每日一题(2023年11月ing)_第3张图片

这题还是很好看懂的,这个i人啊必须有她喜欢的人favorite[i]坐到她的左右两边(一个圈子)她才会参加(返回数加一)。其实就是找到能满足条件的最大的圈子大小。

思路:

拓扑排序来构建邻接表,然后计算圈子的大小。下面是代码的一般流程:

  1. 统计每个人的入度,即有多少个人喜欢这个人。

  2. 将入度为0的人添加到一个队列中。

  3. 通过BFS(广度优先搜索)遍历队列,计算每个人所在的圈子深度。

  4. 统计两种类型的圈子:小圈子和大圈子。

  5. 对于小圈子,它的最大大小为2,然后加上与它相邀请的人的深度之和。

  6. 对于大圈子,计算最大的圈子大小。
  7. 最后返回小圈子和大圈子中的最大值。

通过拓扑排序和BFS来找到满足条件的最大的圈子大小。

这题很有意思,有点人际交往的东西在里面。

class Solution {
    public int maximumInvitations(int[] favorite) {
        int n = favorite.length;
		int[] indegree = new int[n];
		for (int i = 0; i < n; i++) 
			indegree[favorite[i]]++;
		
		int[] que = new int[n];
		int read = 0, write = 0;
		for (int i = 0; i < n; i++) {
			if (indegree[i] == 0) 
				que[write++] = i;
			
		}
		
		int[] depth = new int[n];
		while (read < write) {
			int cur = que[read++];
			int next = favorite[cur];
			depth[next] = Math.max(depth[next], depth[cur] + 1);
			if (--indegree[next] == 0) 
				que[write++] = next;
			
		}
		int sumOfSmallRings = 0;
		int bigRings = 0;
		for (int i = 0; i < n; i++) {
			if (indegree[i] > 0) {
				int maxSize = 1;
				indegree[i] = 0;

				for (int j = favorite[i]; j != i; j = favorite[j]) {
					maxSize++;
					indegree[j] = 0;
				}

				if (maxSize == 2) 
					sumOfSmallRings += 2 + depth[i] + depth[favorite[i]];
				else 
					bigRings = Math.max(bigRings, maxSize);
				
			}
		}
		return Math.max(sumOfSmallRings, bigRings);
    }
}

力扣刷题篇之每日一题(2023年11月ing)_第4张图片

2.

简单题了,舒服

力扣刷题篇之每日一题(2023年11月ing)_第5张图片

力扣刷题篇之每日一题(2023年11月ing)_第6张图片

容易,找出所有集齐 全部三种颜色 环的杆,并返回这种杆的数量。

数组g存储每根杆上套的所有环,时间空间复杂度均为O(n),n为字符串长度/2即环的个数

class Solution {
    public int countPoints(String rings) {
        // 数组g存储每根杆上套的所有环,时间空间复杂度均为O(n),n为字符串长度/2即环的个数
        int n = rings.length() / 2, ans = 0;
        List[] g = new ArrayList[10];
        for (int i = 0; i < 10; i++) g[i] = new ArrayList();
        for (int i = 0; i < n; i++) g[rings.charAt(2 * i + 1) - '0'].add(rings.charAt(2 * i));
        for (int i = 0; i < 10; i++) if (g[i].contains('R') && g[i].contains('G') && g[i].contains('B')) ans++;
        return ans;
    }
}

力扣刷题篇之每日一题(2023年11月ing)_第7张图片

3.

中等题,但还是很简单的

力扣刷题篇之每日一题(2023年11月ing)_第8张图片

力扣刷题篇之每日一题(2023年11月ing)_第9张图片

这题其实就是层序遍历,填充他的next指针。

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;

    public Node() {}
    
    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, Node _left, Node _right, Node _next) {
        val = _val;
        left = _left;
        right = _right;
        next = _next;
    }
};
*/

class Solution {
    public Node connect(Node root) {
      if(root==null){
          return root;
      }  
      Node cur=root;
      while(cur!=null){//遍历完
        //   dummy是每层的头,pre负责构建,cur是指代当前层
          Node dummy=new Node(0);
          Node pre = dummy;
          while(cur!=null){//到了NULL就说明每层结束了
              if(cur.left!=null){
                  pre.next=cur.left;
                  pre=pre.next;
              }
              if(cur.right!=null){
                  pre.next=cur.right;
                  pre=pre.next;

              }
              cur=cur.next;
          }
          cur=dummy.next;//指向下一层的第一个元素
      }
      return root;
    }
}

力扣刷题篇之每日一题(2023年11月ing)_第10张图片

4.

力扣刷题篇之每日一题(2023年11月ing)_第11张图片

这个题最容易想到的是O(n^2)的暴力解法。

为了更高效地找到数组中两个数的最大异或值,可以使用更优化的算法,例如基于前缀树(Trie)的方法。这种方法可以将时间复杂度优化到 O(n),从而提高算法的效率。

基于前缀树的方法涉及构建一个 Trie 数据结构,其中存储了数组中的数字的二进制表示。通过遍历数组中的每个数字,并在 Trie 中查找与当前数字的异或结果最大的另一个数字,可以找到数组中两个数的最大异或值。

前缀树的学习资料:

【【数据结构 10】Trie|前缀树|字典树】https://www.bilibili.com/video/BV1Az4y1S7c7?vd_source=70cd9a7d58eaf79ee46e9bddc1d0d53e

class TrieNode {
    TrieNode[] children;

    TrieNode() {
        children = new TrieNode[2];
    }
}

class Solution {
    public int findMaximumXOR(int[] nums) {
        TrieNode root = new TrieNode();
        int maxXOR = 0;

        for (int num : nums) {
            insertNumber(root, num);
            int currXOR = findXOR(root, num);
            maxXOR = Math.max(maxXOR, currXOR);
        }

        return maxXOR;
    }

    private void insertNumber(TrieNode root, int num) {
        TrieNode curr = root;

        for (int i = 31; i >= 0; i--) {
            int bit = (num >> i) & 1;

            if (curr.children[bit] == null) {
                curr.children[bit] = new TrieNode();
            }

            curr = curr.children[bit];
        }
    }

    private int findXOR(TrieNode root, int num) {
        TrieNode curr = root;
        int xor = 0;

        for (int i = 31; i >= 0; i--) {
            int bit = (num >> i) & 1;
            int oppositeBit = bit == 1 ? 0 : 1;

            if (curr.children[oppositeBit] != null) {
                xor |= (1 << i);
                curr = curr.children[oppositeBit];
            } else {
                curr = curr.children[bit];
            }
        }

        return xor;
    }
}

力扣刷题篇之每日一题(2023年11月ing)_第12张图片

class Solution {
    public int findMaximumXOR(int[] nums) {

        int max = Integer.MIN_VALUE;

        for(int n:nums)
        {
            max = Math.max(max,n);
        }

        
        int highestBitPos = 31 - Integer.numberOfLeadingZeros(max);

        int res = 0;
        int mask = 0;

        Set set;

        for(int i=highestBitPos;i>=0;i--)
        {
            set = new HashSet<>();
            mask = mask | (1 << i);
            int candidateRes = res | (1 << i);
            for(int n:nums)
            {
                n = n & mask;
                if(set.contains(candidateRes ^ n))
                {
                    res = candidateRes;
                    break;
                }
                set.add(n);
            }
        }

        return res;



    }
}

力扣刷题篇之每日一题(2023年11月ing)_第13张图片

5.

力扣刷题篇之每日一题(2023年11月ing)_第14张图片

找长度为10,出现过两次及以上的子序列。

方法一,用哈希表

遍历字符串,把所有十个连续的子序列存进map里,每出现一次value加一,value等于2时就能加入ansl了。

class Solution {
    public List findRepeatedDnaSequences(String s) {
        int n = s.length();
        List ansL = new ArrayList<>();
        if (n <= 10) return ansL;
        Map map = new HashMap<>();
        for (int i = 0; i <= n - 10; i++) {
            String ans = s.substring(i, i + 10);
            map.put(ans, map.getOrDefault(ans, 0) + 1);
            if (map.get(ans) == 2) ansL.add(ans);
        }
        return ansL;
    }
}

力扣刷题篇之每日一题(2023年11月ing)_第15张图片

方法二、滑动窗口+哈希表

力扣刷题篇之每日一题(2023年11月ing)_第16张图片

import java.util.AbstractList;
class Solution {
    public static List findRepeatedDnaSequences(String s) {
        int n = s.length();
        Map cMap = new HashMap<>() {{
            put('A', 0);
            put('C', 1);
            put('G', 2);
            put('T', 3);
        }};
        return new AbstractList() {
            private final List list = new ArrayList<>();

            private final Map map = new HashMap<>();

            @Override
            public String get(int index) {
                init();
                return list.get(index);
            }

            @Override
            public int size() {
                init();
                return list.size();
            }

            void init() {
                if (list.isEmpty() && n > 10) {
                    findRepeatedDnaSequences();
                }
            }

            void findRepeatedDnaSequences() {
                int code = 0;
                for (int i = 0; i < 10; i++) {
                    code = (code << 2) + cMap.get(s.charAt(i));
                }
                map.put(code, 1);
                for (int i = 10; i < n; i++) {
                    code &= (1 << 18) - 1;
                    code = (code << 2) + cMap.get(s.charAt(i));
                    int count = map.getOrDefault(code, 0);
                    if (count == 1) {
                        list.add(s.substring(i - 9, i + 1));
                    }
                    map.put(code, count + 1);
                }
            }
        };
    }
}

力扣刷题篇之每日一题(2023年11月ing)_第17张图片

6

力扣刷题篇之每日一题(2023年11月ing)_第18张图片

 位运算+暴力枚举:

首先,创建一个整型数组 store,用于存储每个字符串的二进制表示。

然后,遍历字符串数组 words,对每个字符串进行处理。

对于每个字符串 s,遍历其中的每个字符,并计算字符相对于字符 'a' 的偏移量。根据偏移量,使用位运算来设置相应的二进制位。

在内层循环中,首先计算 tag,表示字符在当前字符串的二进制表示中对应位的值。如果 tag 等于 0,说明该字符在当前字符串中是第一次出现,将相应的二进制位设置为 1。

完成字符串的二进制表示后,接下来的嵌套循环用于比较每对字符串的二进制表示。

对于每对字符串的二进制表示,使用位运算的与操作 (store[i] & store[p]),如果结果为 0,说明两个字符串没有相同的字母。

如果两个字符串没有相同的字母,则计算它们的长度乘积 res,并更新最大乘积 ans

最后,返回最大乘积 ans

class Solution {
    public int maxProduct(String[] words) {
        //思路:直接用位运算
        int[] store=new int[words.length];
        for(int i=0;i

 力扣刷题篇之每日一题(2023年11月ing)_第19张图片

优化:

首先对每个字符串进行预处理,将其转换为一个包含字符出现情况的位向量(bitmask),出现的位在二进制上的偏移置为1,方便后续计算。然后,对于每一对字符串,如果它们的位向量按位与的结果为0,则它们没有相同的字母,可以计算它们的长度乘积并更新最大乘积。

class Solution {
    public int maxProduct(String[] words) {
        int n = words.length;

        // 预处理,将每个字符串转换为位向量
        int[] bitmasks = new int[n];
        for (int i = 0; i < n; i++) {
            String word = words[i];
            int bitmask = 0;
            for (char c : word.toCharArray()) {
                bitmask |= 1 << (c - 'a'); // 将对应的位设置为1
            }
            bitmasks[i] = bitmask;
        }

        int maxProduct = 0;
        for (int i = 0; i < n - 1; i++) {
            for (int j = i + 1; j < n; j++) {
                // 如果两个字符串的位向量按位与的结果为0,则它们没有相同的字母
                if ((bitmasks[i] & bitmasks[j]) == 0) {
                    int product = words[i].length() * words[j].length();
                    maxProduct = Math.max(maxProduct, product);
                }
            }
        }

        return maxProduct;
    }
}

力扣刷题篇之每日一题(2023年11月ing)_第20张图片

7.

简单题,我哭死

力扣刷题篇之每日一题(2023年11月ing)_第21张图片

判断首尾是不是元音字符串就好了。 

class Solution {
    public int vowelStrings(String[] words, int left, int right) {
        int res=0;
        for(int i=left;i<=right;i++){
            String s=words[i];
            int n=s.length();
            if((s.charAt(0)=='a'||s.charAt(0)=='e'||s.charAt(0)=='i'||s.charAt(0)=='o'||s.charAt(0)=='u') && (s.charAt(n-1)=='a'||s.charAt(n-1)=='e'||s.charAt(n-1)=='i'||s.charAt(n-1)=='o'||s.charAt(n-1)=='u')) res++;
        }
        return res;
    }
}

 力扣刷题篇之每日一题(2023年11月ing)_第22张图片

 力扣刷题篇之每日一题(2023年11月ing)_第23张图片

  • 在循环中,初始化变量 a 和 b 为 0,分别表示以 0 和 1 结尾的平衡子字符串的长度。
  • 在第一个 while 循环中,判断索引 idx 是否小于 n,并且字符串 s 在索引 idx 处的字符是否为 '0',如果是则进入循环体。
    • 将 a 自增 1,并且判断 a 是否大于等于 0。
    • 将索引 idx 自增 1。
  • 在第二个 while 循环中,同样判断索引 idx 是否小于 n,并且字符串 s 在索引 idx 处的字符是否为 '1',如果是则进入循环体。
    • 将 b 自增 1,并且判断 b 是否大于等于 0。
    • 将索引 idx 自增 1。
  • 计算当前平衡子字符串的长度,取 a 和 b 的较小值乘以 2,并将结果与 ans 进行比较,取较大值更新 ans
class Solution {
    public int findTheLongestBalancedSubstring(String s) {
        int n = s.length(), idx = 0, ans = 0;
        while (idx < n) {
            int a = 0, b = 0;
            while (idx < n && s.charAt(idx) == '0' && ++a >= 0) idx++;
            while (idx < n && s.charAt(idx) == '1' && ++b >= 0) idx++;
            ans = Math.max(ans, Math.min(a, b) * 2);
        }
        return ans;
    }
}

力扣刷题篇之每日一题(2023年11月ing)_第24张图片

9

力扣刷题篇之每日一题(2023年11月ing)_第25张图片

力扣刷题篇之每日一题(2023年11月ing)_第26张图片

力扣刷题篇之每日一题(2023年11月ing)_第27张图片

力扣刷题篇之每日一题(2023年11月ing)_第28张图片

bfs,我先CV 

// class Solution {
//     // 二分+bfs(预处理+验证路径)
//     // 将矩阵可达点预处理为着火时间,后续bfs搜索路径时,到达时间小于着火时间的为可走路径。
//     // 可暂停时间的最小值为0,最大值为无穷大,而无穷大状态即火焰扩张完所有可达位置后,
//     // 矩阵中仍存在从左上到右下角的安全路径,所以可暂停时间time可设置为火焰完成扩张时间+2,
//     // 即ans可能取[0,time]内任何值,在此区间内二分查找不存在可达路径的暂停时间最小值,
//     // 判定合法的方式就是对每个时间t在预处理过后的矩阵内搜索是否存在左上到右下的安全路径,
//     // 1、若t=0时不可到达目标点,则永远不可达成,返回-1,
//     // 2、若t=time,而在time-1时存在安全路径,而火焰完成扩张的时间是time-2,所以火焰不在扩张后仍存在安全路径,是否可达与暂停时间无关,返回1e9,
//     // 3、其余情况下则是火扩张至某时刻后目标点不在可达,那么二分求的是最小不可达时间r,r-1即为最大可达目标点的暂停时间。
//     int[][] g;
//     int m, n;
//     int[][] dir = {{-1,0},{0,1},{1,0},{0,-1}};
//     public int maximumMinutes(int[][] g) {
//         this.g = g;
//         m = g.length;
//         n = g[0].length;
//         Deque que = new ArrayDeque<>();
//         boolean[][] vis = new boolean[m][n];
//         // 预处理矩阵,将所有墙壁点标记为-1,这样就可以用0代表空地,以及大于0的数字代表每个位置开始着火的时间。
//         // 将初始火源点存入队列,后续bfs按圈扩张,标记所有
//         for(int i = 0; i < m; ++i){
//             for(int j = 0; j < n; ++j){
//                 if(g[i][j] == 2){
//                     g[i][j] = -1;
//                 }else if(g[i][j] == 1){
//                     que.offer(new int[]{i, j});
//                     vis[i][j] = true;
//                 }
//             }
//         }                 
//         int time = 1;
//         // bfs分层模拟扩展随时间可被火焰蔓延的区域,在g矩阵标记着火时间点,time最终为火焰铺满所有可蔓延位置所需的时间。
//         while(!que.isEmpty()){
//             int len = que.size();
//             while(--len >= 0){
//                 int[] p = que.poll();
//                 for(int k = 0; k < 4; ++k){
//                     int i = p[0] + dir[k][0], j = p[1] + dir[k][1];
//                     if(i >= 0 && j >= 0 && i < m && j < n && !vis[i][j] && g[i][j] == 0){
//                         g[i][j] = time;
//                         que.offer(new int[]{i, j});
//                         vis[i][j] = true;
//                     }
//                 }
//             }
//             ++time;
//         }
//         // 二分找到无法到达的最小暂停时间r,则r-1即为最大可暂停时间。
//         int l = 0, r = time;
//         while(l < r){
//             int mid = l + r >> 1;
//             if(!bfs(mid))
//                 r = mid;
//             else
//                 l = mid + 1;
//         }
//         // 若直接出发仍无法到达,则-1不可实现;若火焰完成扩张后+1秒仍可到达,因火焰不会在扩张,所以说明后续仍可到达。
//         // 否则返回最小无法到达暂停时间r-1即可。
//         if(r == 0)
//             return -1;
//         else if(r == time)
//             return 1000000000;
//         else
//             return r-1;
//     }
//     // bfs验证在预留t时间的火势状态下,是否能够从左上角走到右下角。
//     public boolean bfs(int t){
//         ++t;
//         boolean[][] vis = new boolean[m][n];
//         Deque que = new ArrayDeque<>();
//         que.offer(new int[]{0,0});
//         vis[0][0] = true;
//         // 当
//         while(!que.isEmpty()){
//             int len = que.size();
//             while(len-- > 0){
//                 int[] p = que.poll();
//                 for(int k = 0; k < 4; ++k){
//                     int i = p[0] + dir[k][0], j = p[1] + dir[k][1];
//                     if(i >= 0 && j >= 0 && i < m && j < n && !vis[i][j] && (g[i][j] >= t || g[i][j] == 0)){
//                         // 到达终点(m-1,n-1)则true。
//                         if(i == m - 1 && j == n - 1)
//                             return true;
//                         if(g[i][j] > t || g[i][j] == 0)
//                             que.offer(new int[]{i, j});
//                         vis[i][j] = true;
//                     }
//                 }
//             }
//             // 若中途终点被火蔓延,则后续也无法再到达,直接false。
//             if(g[m-1][n-1] == t)
//                 return false;
//             ++t;
//         }
//         return false;
//     }
// }

class Solution {
    static int[][] directions = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};
    public int maximumMinutes(int[][] grid) {
        int m = grid.length, n = grid[0].length;
        int[][] fire = new int[m][n];
        int[][]people = new int[m][n];
        for (int i = 0; i < m; i++) {
            Arrays.fill(fire[i], -1);
            Arrays.fill(people[i], -1);
        }
        Deque que = new ArrayDeque<>();
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 1) {
                    fire[i][j] = 0;
                    que.offer(new int[]{i, j, 0});
                }
            }
        }
        while (!que.isEmpty()) {
            int[] cur = que.poll();
            for (int[] d: directions) {
                int nx = cur[0] + d[0], ny = cur[1] + d[1];
                if (nx >= 0 && ny >= 0 && nx < m && ny < n && fire[nx][ny] == -1 && grid[nx][ny] == 0) {
                    fire[nx][ny] = cur[2] + 1;
                    que.offer(new int[]{nx, ny, cur[2] + 1});
                }
            }
        }

        people[0][0] = 0;
        que = new ArrayDeque<>();
        que.offer(new int[]{0, 0, 0});
        while (!que.isEmpty()) {
            int[] cur = que.poll();
            for (int[] d:directions) {
                int nx = cur[0] + d[0], ny = cur[1] + d[1];
                if (nx >= 0 && ny >= 0 && nx < m && ny < n && people[nx][ny] == -1 && grid[nx][ny] == 0) {
                    people[nx][ny] = cur[2] + 1;
                    if (nx == m - 1 && ny == n - 1) return fire[m - 1][n - 1] == -1 ? (int)1e9 : fire[m - 1][n - 1] - people[m - 1][n - 1] - ((fire[m - 2][n - 1] != fire[m - 1][n - 1] - 1 && people[m - 2][n - 1] == people[m - 1][n - 1] - 1 || fire[m - 1][n - 2] != fire[m - 1][n - 1] - 1 && people[m - 1][n - 2] == people[m - 1][n - 1] - 1) ? 0 : 1);
                    if (people[nx][ny] >= fire[nx][ny] && fire[nx][ny] != -1) continue;
                    que.offer(new int[]{nx, ny, cur[2] + 1});
                }
            }
        }
        return -1;
    }
}

力扣刷题篇之每日一题(2023年11月ing)_第29张图片

10.

力扣刷题篇之每日一题(2023年11月ing)_第30张图片

力扣刷题篇之每日一题(2023年11月ing)_第31张图片
 

// // class Solution {
// //     public int[] successfulPairs(int[] spells, int[] potions, long success) {
// //         int n=spells.length;
// //         int[] res=new int[n];
// //         for(int i=0;i=success) cnt++;
// //             }
// //             res[i]=cnt;
// //         }
// //         return res;
// //     }
// // }

// class Solution {

//     public int[] successfulPairs(int[] spells, int[] potions, long success) {
//         Arrays.sort(potions);
//         int N = spells.length;
//         int M = potions.length;
//         int[] ans = new int[N];
//         for (int i = 0; i < N; i++) {
//             int l = 0;
//             int r = M - 1;
//             int min = -1;
//             while (l <= r) {
//                 int m = (l + r) >>> 1;
//                 if ((long) potions[m] * spells[i] >= success) {
//                     min = m;
//                     r = m - 1;
//                 } else {
//                     l = m + 1;
//                 }
//             }
//             if (min != -1) {
//                 ans[i] = M - min;
//             }
//         }
//         return ans;
//     }
// }

class Solution {
    static int inf = (int)1e5;
    public int[] successfulPairs(int[] spells, int[] potions, long success){
        int max = 0;
        for(int x : spells){
            if(x > max) max = x;
        }
        int minPotion = (int)Math.min(inf, (success - 1) / max);
        int[] count = new int[max + 1];
        for(int potion:potions){
            if(potion > minPotion){
                ++count[(int)((success + potion - 1)/potion)];
            }
        }
        for(int i = 1; i <= max; i++){
            count[i] += count[i-1];
        }
        int n = spells.length;
        int[] result = new int[n];
        for(int i = 0; i < n; i++){
            result[i] = count[spells[i]];
        }
        return result;
    }
}

力扣刷题篇之每日一题(2023年11月ing)_第32张图片

11

力扣刷题篇之每日一题(2023年11月ing)_第33张图片

使用了贪心算法的思想。从左到右遍历数组,对于每一对夫妻,如果他们不坐在一起(即i位置的配偶不是y),则在后面的位置中找到y的位置j,然后交换i位置的配偶和j位置的人。交换次数加1,继续遍历下一对夫妻。最终返回交换次数。

该方法的时间复杂度为O(n^2),其中n是数组row的长度。

class Solution {
    public int minSwapsCouples(int[] row) {
        int count = 0;  // 交换次数计数器
        for (int i = 0; i < row.length; i += 2) {
            int x = row[i];  // 当前位置i的夫妻编号
            int y = x ^ 1;  // x的配偶编号
            if (row[i + 1] != y) {  // 如果i位置的配偶不是y,则需要进行交换
                for (int j = i + 2; j < row.length; j++) {
                    if (row[j] == y) {  // 在后面的位置找到y的位置j
                        int temp = row[i + 1];  // 交换i位置的配偶和j位置的人
                        row[i + 1] = row[j];
                        row[j] = temp;
                        count++;  // 交换次数加1
                        break;
                    }
                }
            }
        }
        return count;  // 返回交换次数
    }
}

力扣刷题篇之每日一题(2023年11月ing)_第34张图片

12

715. Range 模块 - 力扣(LeetCode)

讲实话,我看不懂一点,这个之后还要仔细看看

力扣刷题篇之每日一题(2023年11月ing)_第35张图片

力扣刷题篇之每日一题(2023年11月ing)_第36张图片

// class RangeModule {
//     TreeMap intervals;

//     public RangeModule() {
//         intervals = new TreeMap();
//     }

//     public void addRange(int left, int right) {
//         Map.Entry entry = intervals.higherEntry(left);
//         if (entry != intervals.firstEntry()) {
//             Map.Entry start = entry != null ? intervals.lowerEntry(entry.getKey()) : intervals.lastEntry();
//             if (start != null && start.getValue() >= right) {
//                 return;
//             }
//             if (start != null && start.getValue() >= left) {
//                 left = start.getKey();
//                 intervals.remove(start.getKey());
//             }
//         }
//         while (entry != null && entry.getKey() <= right) {
//             right = Math.max(right, entry.getValue());
//             intervals.remove(entry.getKey());
//             entry = intervals.higherEntry(entry.getKey());
//         }
//         intervals.put(left, right);
//     }

//     public boolean queryRange(int left, int right) {
//         Map.Entry entry = intervals.higherEntry(left);
//         if (entry == intervals.firstEntry()) {
//             return false;
//         }
//         entry = entry != null ? intervals.lowerEntry(entry.getKey()) : intervals.lastEntry();
//         return entry != null && right <= entry.getValue();
//     }

//     public void removeRange(int left, int right) {
//         Map.Entry entry = intervals.higherEntry(left);
//         if (entry != intervals.firstEntry()) {
//             Map.Entry start = entry != null ? intervals.lowerEntry(entry.getKey()) : intervals.lastEntry();
//             if (start != null && start.getValue() >= right) {
//                 int ri = start.getValue();
//                 if (start.getKey() == left) {
//                     intervals.remove(start.getKey());
//                 } else {
//                     intervals.put(start.getKey(), left);
//                 }
//                 if (right != ri) {
//                     intervals.put(right, ri);
//                 }
//                 return;
//             } else if (start != null && start.getValue() > left) {
//                 if (start.getKey() == left) {
//                     intervals.remove(start.getKey());
//                 } else {
//                     intervals.put(start.getKey(), left);
//                 }
//             }
//         }
//         while (entry != null && entry.getKey() < right) {
//             if (entry.getValue() <= right) {
//                 intervals.remove(entry.getKey());
//                 entry = intervals.higherEntry(entry.getKey());
//             } else {
//                 intervals.put(right, entry.getValue());
//                 intervals.remove(entry.getKey());
//                 break;
//             }
//         }
//     }
// }

class RangeModule {

    public Range root;
    public RangeModule() {
        
    }
    
    public void addRange(int left, int right) {
        root = insert(root,left, right-1);
    }
    
    public boolean queryRange(int left, int right) {
        return query(root,left, right-1);
    }
    
    public void removeRange(int left, int right) {
        root = remove(root,left, right-1);
    }
    
    static class  Range{
        public int left, right;
        public Range l, r;
        
        public Range(int left,int right){
            this.left = left;
            this.right = right;
        }
    }
        
    public Range remove(Range range,int left,int right){
        
        if(range == null) return null;
        
        if(right < range.left)
            range.l = remove(range.l, left, right);
        else if(left > range.right)
        
            range.r = remove(range.r, left, right);
        else if(left <= range.left && right >= range.right){
         
            Range l = remove(range.l, left, right);
            Range r = remove(range.r, left, right);
            if(l == null)
                return r;
            else if(r == null)
                return l;
            else{
                if(l.r == null){
                    l.r = r;
                    return l;
                }else{
                    Range temp = r;
                    while(temp.l!=null)
                        temp=temp.l;
                    temp.l = l;
                    return r;
                }
            }

        }else if(left <= range.left){
            range.left = right+1;
            range.l = remove(range.l, left, right);

        }else if(right >= range.right){
            range.right = left - 1;
            range.r = remove(range.r, left, right);

        }else{
           
            Range newR = new Range(right+1, range.right);
            Range r = range.r;
            range.right = left - 1;
            newR.r = r;
            range.r = newR;
        }

        return range;
    }
    public boolean query(Range range,int left,int right){
        
        if(range == null)
            return false;

        if(right < range.left)
            return query(range.l,left,right);
        else if(left > range.right)
            return query(range.r,left,right);
        else if(left >= range.left && right <= range.right)
            return true;
        
        return false;
    }
    
    public Range insert(Range range,int left,int right){
        
        if(range == null)
            return new Range(left, right);
        
        if(right < range.left -1)
            range.l = insert(range.l, left, right);

         else if(left > range.right+1)
            range.r = insert(range.r, left, right);

        else{ 
            int[]info = new int[]{left, right};
            range.l = add(range.l, info, true);
            range.r = add(range.r, info, false);
         range.left = Math.min(range.left, info[0]);       
         range.right = Math.max(range.right, info[1]);
        }
        return range;
    }
    public Range add(Range range,int [] info,boolean isleft){
        
        if(range == null)
            return null;
            
        if(isleft){ 
            if(range.right >= info[0] - 1){ //重叠
                info[0] = Math.min(info[0], range.left);
                return add(range.l, info, isleft);
            }else{
                range.r = add(range.r, info, isleft);
                return range;
            }
        }else if(!isleft){ 
            if(range.left <= info[1]+1){ 
                info[1] = Math.max(info[1], range.right);
                return add(range.r, info, isleft);
            }else{
                range.l = add (range.l, info, isleft);
                return range;
            }
        }
        return range;
    }
}

力扣刷题篇之每日一题(2023年11月ing)_第37张图片

13 

307. 区域和检索 - 数组可修改 - 力扣(LeetCode)

力扣刷题篇之每日一题(2023年11月ing)_第38张图片

力扣刷题篇之每日一题(2023年11月ing)_第39张图片

this.nums=nums;下面这个 通过了但是不好,遍历区间,效果不好

class NumArray {
    private int[] nums;

    public NumArray(int[] nums) {
        this.nums = nums;
    }
    
    public void update(int index, int val) {
        nums[index] = val;
    }
    
    public int sumRange(int left, int right) {
        int sum = 0;
        for (int i = left; i <= right; i++) {
            sum += nums[i];
        }
        return sum; // Add this line to return the computed sum
    }
}

/**
 * Your NumArray object will be instantiated and called as such:
 * NumArray obj = new NumArray(nums);
 * obj.update(index,val);
 * int param_2 = obj.sumRange(left,right);
 */

力扣刷题篇之每日一题(2023年11月ing)_第40张图片

加上双指针,也不太好

class NumArray {
    private int[] nums;

    public NumArray(int[] nums) {
        this.nums = nums;
    }
    
    public void update(int index, int val) {
        nums[index] = val;
    }
    
    public int sumRange(int left, int right) {
        int sum = 0;
        if((left+right)%2==0){
            sum=nums[(left+right)/2];
        }
        
        while(left

力扣刷题篇之每日一题(2023年11月ing)_第41张图片

用上树状数组(Binary Indexed Tree,BIT)来实现动态数组的区间更新和区间查询,有所改进

public class NumArray {
    private int[] nums;   // 存储原始数组
    private int[] tree;   // 树状数组,用于快速计算区间和

    public NumArray(int[] nums) {
        int n = nums.length;
        this.nums = nums;
        tree = new int[n + 1];

        // 初始化树状数组
        for (int i = 1; i <= n; i++) {
            tree[i] += nums[i - 1];
            int nxt = i + (i & -i); // 下一个关键区间的右端点
            if (nxt <= n) {
                tree[nxt] += tree[i];
            }
        }
    }

    public void update(int index, int val) {
        int delta = val - nums[index];
        nums[index] = val;

        // 更新树状数组
        for (int i = index + 1; i < tree.length; i += i & -i) {
            tree[i] += delta;
        }
    }

    // 计算从位置 1 到位置 i 的前缀和
    private int prefixSum(int i) {
        int s = 0;
        for (; i > 0; i &= i - 1) { // i -= i & -i 的另一种写法
            s += tree[i];
        }
        return s;
    }

    public int sumRange(int left, int right) {
        // 计算区间和
        return prefixSum(right + 1) - prefixSum(left);
    }
}

 力扣刷题篇之每日一题(2023年11月ing)_第42张图片

 14

1334. 阈值距离内邻居最少的城市 - 力扣(LeetCode)

力扣刷题篇之每日一题(2023年11月ing)_第43张图片

力扣刷题篇之每日一题(2023年11月ing)_第44张图片

力扣刷题篇之每日一题(2023年11月ing)_第45张图片

 

该算法通过 Floyd-Warshall 算法计算所有城市之间的最短路径,并统计每个城市到其他城市的距离是否满足条件。最后,返回满足条件的城市中,拥有最小邻居数量的城市。

这个算法的时间复杂度为 O(n^3),其中 n 是城市的数量。这是因为它使用了 Floyd-Warshall 算法,该算法的时间复杂度为 O(n^3)。对于小规模的城市数量可能是可接受的,但对于大规模的城市网络,可能会变得很慢。

class Solution {
    public int findTheCity(int n, int[][] edges, int distanceThreshold) {
        // 初始化城市之间的距离矩阵,使用较大的值表示无穷大距离
        int[][] dis = new int[n][n];
        for (int i = 0; i < n; i++) {
            Arrays.fill(dis[i], Integer.MAX_VALUE / 2);
        }

        // 根据边数组更新直接相连城市之间的距离
        for (int[] e : edges) {
            dis[e[0]][e[1]] = e[2];
            dis[e[1]][e[0]] = e[2];
        }

        // 使用 Floyd-Warshall 算法计算所有城市之间的最短路径
        for (int k = 0; k < n; k++) {
            dis[k][k] = 0;
            for (int i = 0; i < n; i++) {
                for (int j = i + 1; j < n; j++) {
                    // 更新城市 i 到城市 j 的最短路径
                    dis[i][j] = dis[j][i] = Math.min(dis[i][j], dis[i][k] + dis[k][j]);
                }
            }
        }

        // 统计每个城市满足条件的邻居数量,并记录邻居数量最小的城市
        int[] ans = new int[]{Integer.MAX_VALUE, -1};
        for (int i = 0; i < n; i++) {
            int cnt = 0;
            for (int j = 0; j < n; j++) {
                // 统计满足条件的邻居数量
                if (dis[i][j] <= distanceThreshold) {
                    cnt++;
                }
            }
            // 更新邻居数量最小的城市信息
            if (cnt <= ans[0]) {
                ans[0] = cnt;
                ans[1] = i;
            }
        }

        // 返回邻居数量最小的城市
        return ans[1];
    }
}

力扣刷题篇之每日一题(2023年11月ing)_第46张图片

总结

这里写一点刷题感受吧,总结一点有规律性的,不同模块的东西吧。

你可能感兴趣的:(算法与数据结构,leetcode,leetcode,算法,java)