领扣 327 计算距离和

题目链接:

​​​​​​lintcode 327


不知道因为什么神奇的原因,这题没有没人写题解,那就在这里记录一下吧!

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;
    }    
    };

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用二分查找算法来解决这个问题。 首先,我们可以将两个数组合并成一个有序数组,然后求出中位数。但是,这个方法的时间复杂度为 $O(m + n)$,不符合题目要求。因此,我们需要寻找一种更快的方法。 我们可以使用二分查找算法在两个数组中分别找到一个位置,使得这个位置将两个数组分成的左右两部分的元素个数之和相等,或者两部分的元素个数之差不超过 1。这个位置就是中位数所在的位置。 具体来说,我们分别在两个数组中二分查找,假设现在在第一个数组中找到了一个位置 $i$,那么在第二个数组中对应的位置就是 $(m + n + 1) / 2 - i$。如果 $i$ 左边的元素个数加上 $(m + n + 1) / 2 - i$ 左边的元素个数等于 $m$ 个,或者 $i$ 左边的元素个数加上 $(m + n + 1) / 2 - i$ 左边的元素个数等于 $m + 1$ 个,则这个位置就是中位数所在的位置。 具体的实现可以参考以下 Java 代码: ```java public double findMedianSortedArrays(int[] nums1, int[] nums2) { int m = nums1.length, n = nums2.length; if (m > n) { // 保证第一个数组不大于第二个数组 int[] tmp = nums1; nums1 = nums2; nums2 = tmp; int t = m; m = n; n = t; } int imin = 0, imax = m, halfLen = (m + n + 1) / 2; while (imin <= imax) { int i = (imin + imax) / 2; int j = halfLen - i; if (i < imax && nums2[j - 1] > nums1[i]) { imin = i + 1; // i 太小了,增大 i } else if (i > imin && nums1[i - 1] > nums2[j]) { imax = i - 1; // i 太大了,减小 i } else { // i 是合适的位置 int maxLeft = 0; if (i == 0) { // nums1 的左边没有元素 maxLeft = nums2[j - 1]; } else if (j == 0) { // nums2 的左边没有元素 maxLeft = nums1[i - 1]; } else { maxLeft = Math.max(nums1[i - 1], nums2[j - 1]); } if ((m + n) % 2 == 1) { // 总元素个数是奇数 return maxLeft; } int minRight = 0; if (i == m) { // nums1 的右边没有元素 minRight = nums2[j]; } else if (j == n) { // nums2 的右边没有元素 minRight = nums1[i]; } else { minRight = Math.min(nums1[i], nums2[j]); } return (maxLeft + minRight) / 2.0; } } return 0.0; } ``` 时间复杂度为 $O(\log\min(m, n))$。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值