乐趣区

关于算法:上岸算法LeetCode-Weekly-Contest-269解题报告

【NO.1 找出数组排序后的指标下标】

解题思路
签到题,循环判断即可。

代码展现

class Solution {
public List<Integer> targetIndices(int[] nums, int target) {

   Arrays.sort(nums);
   List<Integer> res = new ArrayList<>();
   for (int i = 0; i < nums.length; i++) {if (nums[i] == target) {res.add(i);
      }
  }
   return res;

}
}

【NO.2 半径为 k 的子数组平均值】

解题思路
应用前缀和计算区间和。留神应用 long 类型以防止溢出。

代码展现

class Solution {
public int[] getAverages(int[] nums, int k) {

   if (k == 0) {return nums;}
   long[] preSum = new long[nums.length];
   preSum[0] = nums[0];
   for (int i = 1; i < nums.length; i++) {preSum[i] = preSum[i - 1] + nums[i];
  }
   int[] res = new int[nums.length];
   Arrays.fill(res, -1);
   for (int i = k; i + k < nums.length; i++) {
       long sum = 0;
       if (i - k == 0) {sum = preSum[i + k];
      } else {sum = preSum[i + k] - preSum[i - k - 1];
      }
       res[i] = (int) (sum / (long) (k * 2 + 1));
  }
   return res;

}
}

【NO.3 从数组中移除最大值和最小值】

解题思路
贪婪,依照最小的破费移除即可。详见正文。

代码展现

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

   if (nums.length <= 2) {return nums.length;}
   // 找出最大值和最小值的下标,因为 len > 2 且元素互不雷同,所以最终 max 肯定不等于 min
   int min = 0, max = 0;
   for (int i = 1; i < nums.length; i++) {if (nums[i] < nums[min]) {min = i;}
       if (nums[i] > nums[max]) {max = i;}
  }
   // 要移除的元素下标为 max 和 min
   // 此时咱们只关怀下标,谁是最大值谁是最小值不重要
   // 为了不便解决,令 min 为较小的下标
   if (min > max) {
       int t = min;
       min = max;
       max = t;
  }
   int res = 0;
   int left = 0, right = nums.length - 1;
   if (min - left + 1 < right - max + 1) {
       res += min - left + 1; // 贪婪,移除 min 须要更少的操作,先移除 min
       left = min + 1;
       res += Math.min(max - left + 1, right - max + 1); // 而后再移除 max
  } else {
       res += right - max + 1;
       right = max - 1;
       res += Math.min(min - left + 1, right - min + 1);

  }
   return res;

}
}

【NO.4 找出通晓机密的所有专家】

解题思路
并查集,详见正文。

代码展现

class Solution {
public List<Integer> findAllPeople(int n, int[][] meetings, int firstPerson) {

   // 依照工夫点将会议分组
   TreeMap<Integer, List<int[]>> orderedMeetings = new TreeMap<>();
   for (var m : meetings) {if (!orderedMeetings.containsKey(m[2])) {orderedMeetings.put(m[2], new ArrayList<>());
      }
       orderedMeetings.get(m[2]).add(m);
  }
   boolean[] known = new boolean[n];
   known[0] = known[firstPerson] = true;
   while (!orderedMeetings.isEmpty()) {
       // 依照工夫程序解决每一波会议
       var entry = orderedMeetings.pollFirstEntry();
       var curMeetings = entry.getValue();
       // 应用并查集保护以后工夫点产生的所有会议中,有关联的人
       UnionFind uf = new UnionFind(n);
       for (var m : curMeetings) {uf.merge(m[0], m[1]);
      }
       // 枚举所有会议
       // 若会议加入人 m[0] 或 m[1] 通晓机密
       // 则把他们所在的根节点也标记为通晓机密
       for (var m : curMeetings) {if (known[m[0]] || known[m[1]]) {known[uf.find(m[0])] = true;
               known[uf.find(m[1])] = true;
          }
      }
       // 枚举所有的参会人,若他们所在的根节点通晓机密,则把他们也标记为通晓机密
       for (var m : curMeetings) {if (known[uf.find(m[0])] || known[uf.find(m[1])]) {known[m[0]] = true;
               known[m[1]] = true;
          }
      }
  }
   List<Integer> res = new ArrayList<>();
   for (int i = 0; i < n; i++) {if (known[i]) {res.add(i);
      }
  }
   return res;

}
}

class UnionFind {
public UnionFind(int size) {

   f = new int[size];
   Arrays.fill(f, -1);

}

public int find(int x) {

   if (f[x] < 0)
       return x;
   return f[x] = find(f[x]);

}

public boolean merge(int a, int b) {

   int fa = find(a);
   int fb = find(b);
   if (fa == fb)
       return false;
   f[fa] = fb;
   return true;

}

public Map<Integer, List<Integer>> sets() {

   Map<Integer, List<Integer>> res = new HashMap<>();
   for (int i = 0; i < f.length; i++) {int fi = find(i);
       if (!res.containsKey(fi)) {res.put(fi, new ArrayList<>());
      }
       res.get(fi).add(i);
  }
   return res;

}

private int[] f;
}

退出移动版