题目链接:
不知道因为什么神奇的原因,这题没有没人写题解,那就在这里记录一下吧!
ok 这道题暴力解还挺好想的(没错就是你心里的那个暴力解),但显然会t,但也别急先把所求画出来,再慢慢找答案的姿势呗!
这里先说一下初始化的思路,使用哈希表存每个元素出现的所有位置,哈希表的第二维应该是数组之类的。
c++:
for (int i = 0; i < a.size(); i++)
{
mp[a[i]].push_back(i);
}
java:
HashMap<Integer, Integer> st = new HashMap<>();
for (int i = 0; i < a.length; i++) {
if (!mp.containsKey(a[i])) {
ArrayList<Integer> l = new ArrayList<>();
l.add(i);
mp.put(a[i], l);
} else {
ArrayList<Integer> ll = mp.get(a[i]);
ll.add(i);
mp.put(a[i], ll);
}
}
很显然哈希表key之间是相互独立的,两个key之间的计算不会互相干扰。
假设现在我们需要求元素x的所有距离和,元素x出现的位置如下:
pos 5 7 9 11 12 16
很显然对于元素第一次出现的位置所对应的答案=(7-5)+(9-5)+....(16-5),那第二个元素呢 ans=(7-5)+(9-7)+...(16-7),这是我们暴力的思路,对于第一次出现的位置答案的计算,我没想到其他可以简化的思路,但这第二个位置的出现就有点神奇了,画个图看看,毕竟鲁迅曾经说过:没事多画图。
数字上面的线段是位置1的答案,下面的是位置二的答案,我们画条虚线一看,这答案1好像可以用 o(1)的方法直接得出答案2,在这个图上,假设答案1=x,答案二不就=x-(7 和 5 之间的距离)*3吗,那个3 代表的是下面三条红色的东东。
也就是说 5 和 7 之间的距离(我们标注为distance)值得我们关注,那这个3咋来的呢,也许你很快发现了,无非就是7后面有几个空当(下文称这些空当为怪兽)呗,这里注意,怪兽本身互不相同,但这两个元素所包含的怪兽的集合是相同的,如下图:
这样一来,我们就达成了通过答案1可以得出答案2的共识,这道题的大厦已经基本完成了!
咱们继续分析,假设我们现在处在元素x出现的第y次的位置上,那如何求这个位置的答案呢?
根据上文我们可以想到好像可以根据前面的状态推出后面的状态,那么对于第y个位置,前面有y-1个位置,我们应该选哪个位置呢,我这里选择第 y-1 次位置,实际上第一次出现的位置应该也可以,选其他的没啥必要, 现在情况清晰了,每次使用当前的位置的答案推算下一次位置的答案。
问题解决了吗? 好像还没有,我们的例子是用第一次出现的位置来推算第二次出现的位置,这两个位置很特殊,还不能推出一般规律,实际上我们要计算的怪兽不止当前所求元素(前一个位置的元素已经求出)的右侧,其实还有左侧:
其实这些怪兽都很好打,只不过对与右侧,为了得出下一步的答案,我们需要减去这些空当的数目*(两个元素的距离),对于左侧我们需要加上空挡的数目*(两个元素之间的距离)。
具体的关系就是:要求的答案 = ans - 要求的位置*(要求的位置答案右面的空当数)+现在的位置*(现在的位置左面的空当数)。
实际上,这解法只是个常规的操作,下面会提供两种实现方式,其实解法都是一样的,带有注释的写的详细些。
Talk is cheap.Show me the code !!!
ok ,,这里是c++和Java的
第一种实现方式:
c++:
class Solution {
public:
/**
* @param a: an integer array
* @return: an integer array
*/
vector<long long> getDistanceMetrics(vector<int> &a) {
// write your code here.
/*mp用来初始化*/
unordered_map<long long , vector<long long>>mp;
/*存的是左面的空挡*/
unordered_map<long long, long long>st;
/*存的是上一个已经求出的值*/
unordered_map<long long, long long>mpp;
/*存的是上一个已求出位置的下标*/
unordered_map<long long, long long>mppp;
vector<long long >ans;
for (int i = 0; i < a.size(); i++)
{
mp[a[i]].push_back(i);
}
for (int i = 0; i < a.size(); i++)
{
long long anss = 0;
if (mp[a[i]].size() > 1)//算出这个元素第一次出现时的答案,并记录相应值。
{
if (st[a[i]] == 0/*st.find(a[i])==st.end()*/)
{
//求值
for (int j = 1; j < mp[a[i]].size(); j++)
{
anss = anss + (mp[a[i]][j] - i);
}
//记录对应值
st[a[i]]=1;
mpp[a[i]] = anss;
ans.push_back(anss);
mppp[a[i]] = i;
}
else//使用已经求出的答案计算现在的答案,并更新。
{
long long distance= i - mppp[a[i]];
long long right= (mp[a[i]].size() - st[a[i]]-1 ) * (-1);//右边空当
long long left = (st[a[i]] - 1);//左边空当
anss = mpp[a[i]] + (distance*(left + right));
/*更新操作*/
mpp[a[i]] = anss;
ans.push_back(anss);
mppp[a[i]] = i;
st[a[i]]++;
}
}
else//要是元素只出现一次那答案可以直接存0了。
ans.push_back(0);
}
return ans;
}
};
java:
这里对照
public class Solution {
/**
* @param a: an integer array
* @return: an integer array
*/
public List<Long> getDistanceMetrics(int[] a) {
// write your code here.
/*mp用来初始化*/
HashMap<Integer, ArrayList<Integer>> mp = new HashMap<>();
/*存的是上一个已经求出的值*/
HashMap<Integer, Long> mpp = new HashMap<>();
/*存的是上一个已求出位置的下标*/
HashMap<Long, Long> mppp = new HashMap<>();
/*存的是左面的空挡*/
HashMap<Integer, Integer> st = new HashMap<>();
/*mp用来初始化,这个是初始化的操作*/
for (int i = 0; i < a.length; i++) {
if (!mp.containsKey(a[i])) {
ArrayList<Integer> l = new ArrayList<>();
l.add(i);
mp.put(a[i], l);
} else {
ArrayList<Integer> ll = mp.get(a[i]);
ll.add(i);
mp.put(a[i], ll);
}
}
List<Long> res = new ArrayList<>();
for (int i = 0; i < a.length; i++) {
long ans = 0;
if (mp.get(a[i]).size() > 1) { //算出这个元素第一次出现时的答案,并记录相应值。
if (!st.containsKey(a[i])) {
//求值
for (int j = 1; j < mp.get(a[i]).size(); j++)
ans = ans + mp.get(a[i]).get(j) - i;
res.add(ans);
//记录对应值
st.put(a[i], 1);
mpp.put(a[i], ans);
/* System.out.println(a[i]);*/
if (!mpp.containsKey(a[i]))
System.out.println(a[i]);
mppp.put((long) a[i], (long) i);
} else { //使用已经求出的答案计算现在的答案,并更新。
long distance = i - mppp.get((long) a[i]);
long right = (mp.get(a[i]).size() - st.get(a[i]) - 1) * (long) (-1);//右边空当
long left = st.get(a[i]) - 1; //左边空当
//更新记录。
ans = mpp.get(a[i]) + (distance * (left + right));
mpp.put(a[i], (long) ans);
st.put(a[i], st.get(a[i]) + 1);
res.add(ans);
mppp.put((long) a[i], (long) i);
}
} else
res.add((long) 0);
}
return res;
}
}
第二种实现方式:
c++:
class Solution {
public:
/**
* @param a: an integer array
* @return: an integer array
*/
vector<long long> getDistanceMetrics(vector<int> &a) {
// write your code here.
unordered_map<int, vector<int>>mp;
vector<long long>ans(a.size());
for(int i=0;i<a.size();i++)
mp[a[i]].push_back(i);
for (auto it = mp.begin(); it != mp.end(); it++)
{
if (it->second.size() > 1)
{
long long st = 0;
long long mpp;
long long mppp;
long long anst = 0;
if(st==0)
for (int j = 1; j < it->second.size(); j++)
{
anst = anst + (it->second[j]- it->second[0]);
}
ans[it->second[0]] = anst;
st = 1;
mpp = anst;
mppp = it->second[0];
int temp = 1;
while (temp<it->second.size())
{
long long distance = it->second[temp] - mppp;
long long right = (it->second.size() - st - 1) * (-1);//右边空当
long long left = (st - 1);//左边空当
anst = mpp + (distance * (left + right));
/*更新操作*/
mpp = anst;
ans[it->second[temp]] = anst;
mppp = it->second[temp];
st++;
temp++;
}
}
else
{
ans[it->second[0]] = 0;
}
}
return ans;
}
};
java:
public class Solution {
/**
* @param a: an integer array
* @return: an integer array
*/
public List<Long> getDistanceMetrics(int[] a) {
// write your code here.
/*mp用来初始化*/
HashMap<Integer, ArrayList<Integer>> mp = new HashMap<>();
ArrayList ans=new ArrayList<>();
for(int i=0;i<a.length;i++)
ans.add((long)0);
System.out.println(ans.size());
for (int i = 0; i < a.length; i++) {
if (!mp.containsKey(a[i])) {
ArrayList<Integer> l = new ArrayList<>();
l.add(i);
mp.put(a[i], l);
} else {
ArrayList<Integer> ll = mp.get(a[i]);
ll.add(i);
mp.put(a[i], ll);
}
}
for (Integer key : mp.keySet()) {
if (mp.get(key).size() > 1) {
long st = 0;
long mpp;
long mppp;
long anss = 0;
if (st == 0) {
for (int j = 1; j < mp.get(key).size(); j++)
anss = anss + mp.get(key).get(j) - mp.get(key).get(0);
}
ans.set(mp.get(key).get(0), anss);
st = 1;
mpp = anss;
mppp = mp.get(key).get(0);
int temp = 1;
while (temp < mp.get(key).size()) {
long distance = mp.get(key).get(temp) - mppp;
long right = (mp.get(key).size() - st - 1) * (-1);//右边空当
long left = (st - 1);//左边空当
anss = mpp + (distance * (left + right));
/*更新操作*/
mpp = anss;
ans.set(mp.get(key).get(temp), anss);
mppp = mp.get(key).get(temp);
st++;
temp++;
}
} else
ans.set(mp.get(key).get(0), (long)0);
}
return ans;
}
};