我尝试在hackerrank中解决一个问题,即在数组中找到最大度数的最小子数组的长度。数组的最大度数是具有最大频率的元素的数量。例如,考虑示例{2,2,1,2,3,1,1} min子阵列长度为4,因为2具有最大度,而具有3度的最小子阵列是{2,2, 1,2}
以下是我解决问题的方法
public class FindingMinSubArrayWithDegree {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
System.out.println(degreeOfArray(arr));
sc.close();
}
static int degreeOfArray(int[] arr) {
HashMap<Integer, Integer> numbersByDegree = new HashMap<Integer, Integer>();
for (int i = 0; i < arr.length; i++) {
int degree = numbersByDegree.getOrDefault(arr[i], 0);
numbersByDegree.put(arr[i], degree + 1);
}
List<Map.Entry<Integer, Integer>> sortedEntries = sortByValue(numbersByDegree);
int maxDegree = sortedEntries.get(0).getValue();
int[] degreeArr = new int[arr.length] ;
int minSubArrayLength = arr.length;
for (Map.Entry<Integer, Integer> entry : sortedEntries) {
if (entry.getValue() < maxDegree) {
break;
}
boolean startIndexFound = false, endIndexFound = false;
int startIndex = 0, endIndex = 0;
for (int i = 0; i < arr.length; i++) {
if (entry.getKey() == arr[i]) {
if (i - 1 >= 0)
degreeArr[i] = degreeArr[i - 1] + 1;
else
degreeArr[i] = 1;
} else {
if (i - 1 >= 0)
degreeArr[i] = degreeArr[i - 1];
}
if (!startIndexFound && degreeArr[i] == 1) {
startIndex = i;
startIndexFound = true;
}
if (!endIndexFound && degreeArr[i] == entry.getValue()) {
endIndex = i;
endIndexFound = true;
}
if (startIndexFound && endIndexFound)
break;
}
startIndexFound = false; endIndexFound = false;
if ((endIndex - startIndex) < minSubArrayLength) {
minSubArrayLength = endIndex - startIndex;
}
for (int i = 0; i < degreeArr.length; i++)
degreeArr[i] = 0;
}
return minSubArrayLength + 1;
}
private static <K, V extends Comparable<? super V>> List<Map.Entry<K, V>>
sortByValue(Map<K, V> map) {
List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>(map.entrySet());
Collections.sort( list, new Comparator<Map.Entry<K, V>>() {
public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
return (o2.getValue()).compareTo( o1.getValue() );
}
});
return list;
}
}
对于像{1,1,2,2,3,3,4,4}这样的输入,这种方法的运行时间最差为O(N ^ 2)。这个问题有更好的算法吗?
PS - 我试过在代码审查中提出这个问题,但没有得到任何回复,这就是为什么搬到这里
答案 0 :(得分:12)
要找到数组的度数,我们只需要跟踪数组中每个不同元素的频率,那些具有最高频率的元素就是度数。
因此,要找到具有最大度数的子数组,我们只需要关心包含具有最大计数的元素的子数组,这意味着所有具有[start , end]
的子数组都是开始,结束该元素。
因此,我们需要做的是跟踪每个元素的频率,开始和结束位置。
伪代码:
int max = 0;
Map<Integer, Integer> map = new HashMap<>();
Map<Integer, Integer> startIndex = new HashMap<>();
Map<Integer, Integer> endIndex = new HashMap<>();
for(int i = 0; i < data.length; i++){
int value = data[i];
if(map.containsKey(value)){
map.put(value, map.get(value) + 1);
}else{
startIndex.put(value, i);
map.put(value, 1);
}
endIndex.put(value, i);
max = Integer.max(max, map.get(value));//Calculate the degree of the array
}
int result = data.length;
for(int i : map.keySet()){
if(map.get(i) == max){
int len = endIndex.get(i) - startIndex.get(i) + 1;
result = Integer.min(result, len);
}
}
return result;
时间复杂度为O(n)
答案 1 :(得分:2)
给定非空整数nums的非空数组,此数组的度数被定义为其任何一个元素的最大频率。
我们将创建3个HashMap。
然后我们将迭代Count(HashMap)并比较最大频率,如果等于最大频率,那么我们将找到(连续)子阵列的长度。
代码: -
class Solution {
public int findShortestSubArray(int[] nums) {
int n = nums.length;
int degree = 0;
HashMap<Integer,Integer> count = new HashMap<Integer,Integer>();
HashMap<Integer,Integer> left = new HashMap<Integer,Integer>();
HashMap<Integer,Integer> right = new HashMap<Integer,Integer>();
for(int i = 0;i<n;i++){
count.put(nums[i],count.getOrDefault(nums[i],0)+1);
if(!left.containsKey(nums[i]))left.put(nums[i],i);
right.put(nums[i],i);
degree = Math.max(degree,count.get(nums[i]));
}
int len ;
int result = n;
for(int c : count.keySet()){
if(count.get(c)==degree){
len = right.get(c)-left.get(c)+1;
if(len < result)
result = len;
}
}
return result;
}
}
时间复杂性O(N) Space Complexcity O(N)
答案 2 :(得分:0)
JavaScript解决方案:
function findShortestSubArray(nums) {
// Elements is a map of key => elementInfo
// with key being each of the elements in the array
// and elementInfo being the object with properties count, leftIndex, rightIndex for
// one particular element in the array
let degree = 0
const elementsInfoHighestCount = new Map()
let subArray = []
const elements = nums.reduce((acc, num, index) => {
let count
let leftIndex
let rightIndex
if (acc.has(num)) {
const existing = acc.get(num)
count = existing.count + 1
leftIndex = existing.leftIndex
rightIndex = index
} else {
count = 1
leftIndex = index
rightIndex = index
}
return acc.set(num, { count, leftIndex, rightIndex })
}, new Map())
// Determine the degree by looping through elements map
elements.forEach((element, uniqueNum) => {
if (element.count === degree) {
elementsInfoHighestCount.set(uniqueNum, element)
} else if (element.count > degree) {
elementsInfoHighestCount.clear()
elementsInfoHighestCount.set(uniqueNum, element)
degree = element.count
}
})
// Get the shortest subarray array by looping through the elementInfoHighestCount map
let result = elementsInfoHighestCount.values().next().value
if (elementsInfoHighestCount.size === 1) {
subArray = nums.slice(result.leftIndex, result.rightIndex + 1)
} else if (elementsInfoHighestCount.size > 1) {
elementsInfoHighestCount.forEach((element, num) => {
const thisElementDiff = element.rightIndex - element.leftIndex
const previousElementDiff = result.rightIndex - result.leftIndex
if (thisElementDiff - previousElementDiff < 0) {
result = elementsInfoHighestCount.get(num)
}
})
subArray = nums.slice(result.leftIndex, result.rightIndex + 1)
}
return subArray.length
};
// Time complexity: O(N)
// Testcases - [1, 2, 2, 3, 1], [1,2,2,3,1,4,2]
答案 3 :(得分:0)
在Python中:
此数组的度数定义为其任何元素的最大频率。请注意,您需要三个字典来保存数量和位置
def codeHere(arrayinput):
numItems = len(arrayinput)
degree = 0
left = dict()
count = dict()
right = dict()
lenght = 0
result = numItems
for i in range(numItems):
x = arrayinput[i]
if (x not in count):
count[x] = 1
left[x] = i
else:
count[x] += 1
right[x] = i
if (count[x] > degree):
degree = count[x]
for i in count.keys():
if(count[i] == degree):
lenght=right[i] - left[i] + 1
if(lenght<result):
result=lenght
return (result)