200 सरणी + तत्वों वाले 2 सरणी तत्वों का न्यूनतम उत्पाद खोजने का सबसे तेज़ तरीका


13

मेरे पास एक सरणी है a[n]। नंबर nहमारे द्वारा दर्ज किया गया है। मुझे निम्न उत्पाद खोजने की आवश्यकता है a[i]और a[j]यदि:

1) abs(i - j) > k

2) a[i] * a[j]को कम से कम किया जाता है

यहाँ मेरा समाधान है (बहुत भोला है):

#include <iostream>
using namespace std;
#define ll long long
int main() {
    ll n,k; cin >> n >> k;

    ll a[n]; for(ll i=0;i<n;i++) cin >> a[i];

    ll mn; bool first = true;

    for(ll i=0;i<n;i++) {
        for(ll j=0;j<n;j++) {
            if(i!=j)
            if(abs(i-j) > k) {
                if(first) {
                    mn = a[i]*a[j];
                    first = false;
                } else if(a[i]*a[j] < mn) mn = a[i]*a[j];
            }
        }
    }
    cout << mn << endl;
}

लेकिन मैं जानना चाहता हूं कि क्या दूरी के साथ एक न्यूनतम उत्पाद खोजने का कोई तेज़ तरीका है?


7
मुझे क्यों नहीं # निकलना चाहिए <बिट्स / stdc ++। H>? और सी ++ केवल संकलक विस्तार द्वारा एक परिवर्तनीय लंबाई सरणी प्रदान करते हैं । आप उपयोग क्यों नहीं कर रहे हैं std::vector? @Scheff - सॉर्टिंग मूल "दूरी" रिश्तों को नष्ट कर देगा।
डेविड सी। रंकिन

3
कम से कम चेक if (i!=j) if (abs(i - j) > k)को खत्म किया जा सकता है। बस i + k + 1 पर आंतरिक लूप शुरू करें for (ll j = i + k + 1; j < n; ++j):। firstअगर mnपहले से इनिशियलाइज़ किया गया है तो चेक को समाप्त किया जा सकता है mn = a[0] * a[k + 1];। (हो सकता है, इसे बुलेट-प्रूफ बनाने के लिए शुरू में kजाँच की जानी चाहिए n।) लेकिन यह अभी भी O (N should) है। यह तेजी से करने योग्य होना चाहिए ...
शेफ

2
@PaMMcKenzie कृपया एक इंडेक्स दूरी (या अधिकतम) के साथ न्यूनतम उत्पाद के लिए पहले दस में से कम से कम दो उपयोगी हिट के साथ एक क्वेरी दिखाएं ।
ग्रेबर्ड

1
@PaMMcKenzie "इस सवाल के जवाब को दर्शाने वाले हजारों URL लिंक नहीं तो शायद सैकड़ों हैं।" - कृपया इनमें से कम से कम तीन URL साझा करें।
לעג ברקן

2
यह सवाल कहां से आया? यह ऐसी आवाज़ नहीं करता है जैसे कि बस पतली हवा से बनी हो। मुझे आश्चर्य नहीं होगा अगर यह उन "ऑनलाइन जज" साइटों में से एक है। यदि हां, तो उन साइटों पर संभवत: समस्या का समाधान करने पर लंबी-चौड़ी चर्चाएँ होती हैं, यदि पूर्ण समाधान नहीं।
पॉलमैकेन्जी

जवाबों:


12

यह मानते हुए कि शर्तों को पूरा करने वाले तत्वों की कम से कम एक जोड़ी है और इसमें दो तत्वों का कोई गुणन नहीं है, यह बहुत अधिक हो सकता है। Theta(n-k) समय और Theta(1)स्थान पर सबसे खराब है- और सबसे अच्छा मामला, कुछ इस तरह से:

auto back_max = a[0];
auto back_min = a[0];
auto best = a[0]*a[k+1];

for(std::size_t i=1; i<n-(k+1); ++i) {
    back_max = std::max(back_max, a[i]);
    back_min = std::min(back_min, a[i]);
    best = std::min(best, std::min(a[i+k+1]*back_max, a[i+k+1]*back_min));
}

return best;

यह समय और स्थान दोनों के लिए विषमतम सबसे खराब स्थिति के रूप में इष्टतम है क्योंकि इष्टतम उत्पाद a[0]किसी भी के साथ हो सकता हैn-(k+1) कम से कम दूरी में तत्व केk+1 , इसलिए n-(k+1)समस्या को हल करने वाले किसी भी एल्गोरिदम द्वारा कम से कम पूर्णांक को पढ़ने की आवश्यकता होती है।


एल्गोरिथ्म के पीछे का विचार इस प्रकार है:

इष्टतम उत्पाद के दो तत्वों का उपयोग करता है a , मान लें कि ये हैं a[r]और a[s]। व्यापकता के नुकसान के बिना हम यह मान सकते हैं कि s > rचूंकि उत्पाद सराहनीय है।

प्रतिबंध के कारण abs(s-r) > kइसका तात्पर्य है कि s >= k+1। अभीs प्रत्येक सूचकांक इस स्थिति को संतुष्ट कर सकता है, इसलिए हम इन सूचकांकों पर ध्यान केंद्रित करते हैं। यह iदिखाया कोड में चलना है , लेकिन यह k+1सुविधा (वास्तव में कोई फर्क नहीं पड़ता) के लिए द्वारा स्थानांतरित कर दिया है । प्रत्येक पुनरावृत्ति के लिए हमें i+k+1सबसे बड़े सूचकांक के रूप में शामिल इष्टतम उत्पाद को खोजने और पिछले सर्वोत्तम अनुमान के साथ तुलना करने की आवश्यकता है।

दूरी की आवश्यकता के कारण i+k+1सभी सूचकांकों के साथ जोड़े जाने वाले संभावित सूचकांक छोटे या बराबर होते iहैं। हमें इन सब पर भी ध्यान देना होगा, लेकिन यह अनावश्यक है क्योंकि निर्धारित न्यूनतम से a[i+k+1]*a[j]अधिक के बराबर हैjimin(a[i+k+1]*max(a[j]), a[i+k+1]*min(a[j])) उत्पाद की एकरूपता के कारण (न्यूनतम न्यूनतम और अधिकतम दोनों a[j]खातों के संबंध में न्यूनतम दो के लिए न्यूनतम संभव है) a[i+k+1]या एकरसता के दो संभावित दिशाओं के बराबर या इसके संकेत ।)

के सेट के बाद से a[j]मान जिस पर हम यहाँ का अनुकूलन बस है {a[0], ..., a[i]}जो केवल एक ही तत्व (द्वारा वृद्धि, a[i]में से प्रत्येक चरण में) i, हम बस का ट्रैक रख सकते max(a[j])और min(a[j])उन्हें अद्यतन करने अगर द्वारा एकल चर के साथ a[i]बड़ा या पिछले इष्टतम मूल्यों से छोटा है। यह कोड उदाहरण के साथ back_maxऔर किया जाता है back_min

पुनरावृत्ति ( i=0) का पहला चरण लूप में छोड़ दिया जाता है और इसके बजाय चर के प्रारंभ के रूप में प्रदर्शन किया जाता है।


3
@ ग्रेबियर मुझे उनके आसपास रखने की आवश्यकता नहीं है, क्योंकि a[i+k+1]न्यूनतम और अधिकतम के साथ इष्टतम उत्पाद के लिए केवल संभावित उम्मीदवार हैं।
अखरोट

क्या आप बता सकते हैं कि एल्गोरिथ्म आपके उत्तर में क्यों काम करता है?
मिनाहनी

6

सबसे तेज के बारे में निश्चित नहीं है ।

I <j - k के बिना सरल समस्या के लिए , न्यूनतम उत्पाद दो सबसे छोटे और सबसे बड़े तत्वों के जोड़े के उत्पादों में से है।

तो, (निम्नलिखित बहुत जटिल है, अखरोट का उत्तर देखें )
(• अगर ≤ n
  • balk यदि एक [0] * एक [k + 1] का न्यूनतम उत्पादन शुरू करें)

  • दो गतिशील मिनीमैक्स डेटा संरचनाओं को बनाए रखें और उससे परे
    {} और {a [ j ] के साथ शुरू करें के j }
  • प्रत्येक I से 0 से n - k - 1 तक
    • upToI में एक [ i ] जोड़ें
    • परे aplus से एक [ i + k ] निकालें

    • min ( upToI ) × min ( परे परे ), min ( upToI ) × अधिकतम ( परे ),
      max ( upToI ) × min ( परे ) और max ( upToI ) × अधिकतम ( परे ) के लिए नए न्यूनतम उत्पाद की जांच करें

यह सबसे तेज, कम से कम जटिलता-वार होना चाहिए। यह ओ (एन) समय और भंडारण है।
smttsp

मूल समाधान में जटिलता O (N ** 2) है, आप अपने समाधान की जटिलता का अनुमान कैसे लगाते हैं?
लेनिक

ओ (nlogn) समय हे (एन) अंतरिक्ष (उपयुक्त minmax कार्यान्वयन के लिए)
बूढ़ा

@greybeard। आपको n * logn समय की आवश्यकता क्यों है क्यों बस एक 4 * n सरणी जिसमें न रखते हुए minUpto, maxUpto, minBeyond, maxBeyond(आप दो पुनरावृत्तियों में बना सकते हैं)? फिर, तीसरे पुनरावृत्ति में, प्रत्येक सूचकांक के लिए, न्यूनतम संभव गुणनफल ज्ञात कीजिए।
smttsp

(@smttsp कि की दिशा में एक वैकल्पिक कदम होगा अखरोट का समाधान ।)
बूढ़ा

4

"न्यूनतम परिमाण" के लिए

2 "सबसे छोटे परिमाण" तत्वों को ढूंढें, फिर (जब आपने दो शून्य पाया है या पूरे सरणी को खोजा है), उन्हें गुणा करें।

abs(i - j) > kभाग के बिना "सबसे कम मूल्य" के लिए

3 संभावनाएं हैं:

  • दो उच्चतम (सबसे छोटी परिमाण) ऋणात्मक संख्याएँ

  • दो सबसे कम (सबसे छोटी परिमाण) गैर-नकारात्मक संख्या

  • सबसे कम (सबसे बड़ा परिमाण) ऋणात्मक संख्या और उच्चतम (सबसे बड़ा परिमाण) गैर-ऋणात्मक संख्या

आप सभी 6 मूल्यों की खोज कर सकते हैं और उत्पादों का पता लगा सकते हैं और जो अंत में सबसे अच्छा है।

तथापि; जैसे ही आप एक शून्य देखते हैं आप जानते हैं कि आपको पहले 2 संभावनाओं के बारे में और अधिक जानने की आवश्यकता नहीं है; और जैसे ही आप एक नकारात्मक संख्या और एक गैर-नकारात्मक संख्या देखते हैं, आप जानते हैं कि आप केवल तीसरी संभावना के बारे में परवाह करते हैं।

यह 3 राज्यों के साथ एक परिमित राज्य मशीन की ओर जाता है - "सभी 3 संभावनाओं के बारे में देखभाल", "उत्तर शून्य है जब तक कि एक नकारात्मक संख्या नहीं देखी जाती है" और "केवल अंतिम संभावना के बारे में परवाह है"। इसे 3 छोरों के सेट के रूप में लागू किया जा सकता है, जहां 2 छोरों में कूदते हैं (goto ) दूसरे लूप के बीच में जब राज्य (परिमित राज्य मशीन) के परिवर्तन होते हैं।

विशेष रूप से, यह कुछ अस्पष्ट जैसा लग सकता है (अप्रयुक्त):

   // It could be any possibility

   for(ll i=0;i<n;i++) {
       if(a[i] >= 0) {
            if(a[i] < lowestNonNegative1) {
                lowestNonNegative2 = lowestNonNegative1;
                lowestNonNegative1 = a[i];
            }
            if(lowestNonNegative2 == 0) {
                goto state2;
            }
       } else {
            if(a[i] > highestNegative1) {
                highestNegative2 = highestNegative1;
                highestNegative1= a[i];
            }
            if(lowestNonNegative1 < LONG_MAX) {
                goto state3;
            }
       }
   }
   if(lowestNonNegative2 * lowestNonNegative1 < highestNegative2 * highestNegative1) {
       cout << lowestNonNegative2 * lowestNonNegative1;
   } else {
       cout << highestNegative2 * highestNegative1;
   }
   return;

   // It will be zero, or a negative and a non-negative

   for(ll i=0;i<n;i++) {
state2:
       if(a[i] < 0) {
           goto state3;
       }
   }
   cout << "0";
   return;

   // It will be a negative and a non-negative

   for(ll i=0;i<n;i++) {
state3:
       if(a[i] < lowestNegative) {
           lowestNegative = a[i];
       } else if(a[i] > highestNonNegative) {
           highestNonNegative = a[i];
       }
    }
    cout << lowestNegative * highestNonNegative;
    return;

abs(i - j) > kभाग के साथ "सबसे कम मूल्य" के लिए

इस मामले में आपके पास अभी भी 3 संभावनाएं हैं; और यह "परिमित राज्य मशीन के साथ 3 छोरों" के साथ काम कर सकता है, लेकिन यह बहुत गन्दा / बदसूरत हो जाता है। इस मामले के लिए एक बेहतर विकल्प यह निर्धारित करने के लिए सरणी को पूर्व-स्कैन करने की संभावना है कि क्या कोई शून्य हैं और यदि वे सभी नकारात्मक या सभी सकारात्मक हैं; ताकि पूर्व-स्कैन के बाद आप या तो यह जान सकें कि उत्तर शून्य है या अकेले विशिष्ट संभावना के लिए डिज़ाइन किए गए लूप का चयन करें।


1
सूचकांक अंतर पर निम्न बाउंड k के लिए यह खाता कहां है ?
ग्रेबियार्ड

1
@ ग्रेबियर: यह (मुझे वह हिस्सा याद नहीं है) - कोड को उस खाते में लेने के लिए संशोधित करने की आवश्यकता होगी।
ब्रेंडन

आपको दो शून्य की आवश्यकता क्यों होगी ?
ट्रेंटप

@TrentP: अर्घ - आप सही कह रहे हैं। उत्तर जानने के लिए एक शून्य पर्याप्त है या तो 0 या एक नकारात्मक संख्या है।
ब्रेंडन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.