找到两对数字,以使它们的乘积绝对差最小

时间:2020-02-23 03:38:53

标签: c++ algorithm

问题:

给出一个整数num,找到绝对差值中最接近的两个整数,其乘积等于num + 1或num + 2。

以任意顺序返回两个整数。

我尝试过:

vector<int> closestDivisors(int num) {
    
    if(num == 1)
        return {1,2};
    int first = num + 1, second = num + 2;
    std::vector<int> result(2);        
    auto vec1 = properDivisors(first);
    auto vec2 = properDivisors(second);
    std::map<int, std::pair<int,int>> m;
    int min_k1 = INT_MAX;
    for(auto it1 : vec1)
    {
        for(auto it2 : vec1)
        {
            if (it1 * it2 == first)
            {
                min_k1 = abs(it1-it2);
                m[min_k1] = {it1, it2};
            }
        }
    }
    
    int min_k2 = INT_MAX;
    for(auto it1 : vec2)
    {
        for(auto it2 : vec2)
        {
            if (it1 * it2 == second)
            {
                min_k2 = abs(it1-it2);
                m[min_k2] = {it1, it2};
            }
        }
    }

    for(auto it : m)
    {
        result[0] = it.second.first;
        result[1] = it.second.second;
        if(result.size() == 2)
            break;
    }
    
    
    

    return result;
}


std::vector<long long> properDivisors(int number) {
   std::vector<long long> divisors ;
   for ( int i = 1 ; i < number / 2 + 1 ; i++ )
      if ( number % i == 0 )
     divisors.push_back( i ) ;
   return divisors ;
}

但是我不断超过时间限制。有没有更有效的方法来实现这一目标?

2 个答案:

答案 0 :(得分:2)

使用向量可能会使它变得慢得多。我将按照以下方式进行处理。

lo设置为1,将hi设置为num + 1。这是获得两个整数的起点,两个整数相乘成所需的值之一(与1num + 2比较接近,因此您可以忽略这种可能性)。

然后只需将lohi彼此相对移动(直到它们交叉),以检查乘积以查看其是否等于所需值。这两个数字接近的事实意味着,以后的任何成功都将使它们比以前的更紧密。

唯一棘手的问题是数字之间的相互关系,但这比您想象的要简单。如果乘积小于num + 1,则减小hi意味着它会进一步偏离期望值,因此在这种情况下,您需要增大lo。< / p>

另一方面,乘积大于num + 2表示您应减少hi(增加lo会使乘积升高,从而远离期望值)。 / p>

如果等于num + 1num + 2,则可以选择其中一个。没关系的原因是因为lo + 1hi之间的绝对差异与lohi -1之间的绝对差异相同(a)


例如,这是一个Python程序,可将其显示出来:

num = int(input("Number: "))
lo = 1
hi = num + 1
found = None
while lo <= hi: # Make this '<' if numbers must be different.
    prod = lo * hi
    if prod == num + 1 or prod == num + 2:
        found = (lo, hi)
        mark = ' *'
    else:
        mark = ""
    print(f"Low = {lo}, high = {hi}, product = {prod}{mark}")
    if prod < num + 1:
        lo += 1
    else:
        hi -= 1
print(found)

进行几次跑步:

Number: 3
Low = 1, high = 4, product = 4 *
Low = 1, high = 3, product = 3
Low = 2, high = 3, product = 6
Low = 2, high = 2, product = 4 *
(2, 2)

Number: 10
Low = 1, high = 11, product = 11 *
Low = 1, high = 10, product = 10
Low = 2, high = 10, product = 20
Low = 2, high = 9, product = 18
Low = 2, high = 8, product = 16
Low = 2, high = 7, product = 14
Low = 2, high = 6, product = 12 *
Low = 2, high = 5, product = 10
Low = 3, high = 5, product = 15
Low = 3, high = 4, product = 12 *
Low = 3, high = 3, product = 9
(3, 4)

Number: 100
Low = 1, high = 101, product = 101 *
Low = 1, high = 100, product = 100
Low = 2, high = 100, product = 200
Low = 2, high = 99, product = 198
: : : (lots of stuff irrelevant to final result)
Low = 6, high = 18, product = 108
Low = 6, high = 17, product = 102 *
Low = 6, high = 16, product = 96
Low = 7, high = 16, product = 112
Low = 7, high = 15, product = 105
Low = 7, high = 14, product = 98
Low = 8, high = 14, product = 112
Low = 8, high = 13, product = 104
Low = 8, high = 12, product = 96
Low = 9, high = 12, product = 108
Low = 9, high = 11, product = 99
Low = 10, high = 11, product = 110
Low = 10, high = 10, product = 100
(6, 17)

正如评论中指出的那样,这仅处理正面输入。您还可以通过更改以下内容来满足负面输入的要求:

lo = 1
hi = num + 1

收件人:

lo = -num - 1
hi = num + 1
if lo > hi:
    (lo, hi) = (hi, lo)

这将解决方案的正面领域括起来,增加了一些额外的时间,但仍然非常快。


(a)我对这里的数学只有99.99%的把握,因此,如果有人可以提供反例,我很乐意编辑答案(甚至删除答案,如果尽管在极端情况下很可能会发现存在的任何问题,但我无法解决它,因此可以通过一些简单的预检查就可以解决)。让我知道。

答案 1 :(得分:0)

这是c ++中的代码。

#include <bits/stdc++.h>
using namespace std;
void print_vector(vector<auto> v){
   cout << "[";
   for(int i = 0; i<v.size(); i++){
       if(v.size() - i == 1) {
           cout << v[i];
       } else {
          cout << v[i] << ", ";
       }
   }
   cout << "]"<<endl;
}
class Solution {
public:
   vector <int> getDiv(int x){
      int diff = INT_MAX;
      vector <int> ret(2);
      for(int i = 1; i * i <= x; i++){
         if(x % i == 0){
            int a = i;
            int b = x / i;
            int newDiff = abs(a - b);
            if(newDiff < diff){
               diff = newDiff;
               ret[0] = a;
               ret[1] = b;
            }
         }
      }
      return ret;
   }
   vector<int> closestDivisors(int num) {
      vector <int> op1 = getDiv(num + 1);
      vector <int> op2 = getDiv(num + 2);
      return abs(op1[0] - op1[1]) <= abs(op2[0] - op2[1]) ? op1 : op2;
   }
};
main(){
   Solution ob;
   print_vector(ob.closestDivisors(8));
}

// Output [3,3]

You can run the above code here

Reference

JavaScript代码。

let num = 8; //Input

function getFactors(num) {
  let factors = [1];
  for (let i = 2; i <= Math.sqrt(num); i++) {
    if (num % i === 0) {
      factors.push(i);
      factors.push(num / i);
    }
  }
  factors.push(num);
  return factors;
}

(function getSmallAbsDiff() {
  const factorsNplusOne = getFactors(num + 1).sort((a, b) => a - b);
  const factorsNplusTwo = getFactors(num + 2).sort((a, b) => a - b);

  const minOne = factorsNplusOne[factorsNplusOne.length / 2 - 1];
  const maxOne = factorsNplusOne[factorsNplusOne.length / 2];
  const minTwo = factorsNplusTwo[factorsNplusTwo.length / 2 - 1];
  const maxTwo = factorsNplusTwo[factorsNplusTwo.length / 2];

  maxOne - minOne < maxTwo - minTwo ? console.log(`[${maxOne}, ${minOne}]`) : console.log(`[${maxTwo}, ${minTwo}]`); // Output
})();

Reference