অমীমাংসিত অ্যারেতে একটি ব্যাপ্তি থেকে সর্বাধিক মান পুনরুদ্ধার করা


9

আমার একটি অরসোর্টড অ্যারে আছে । আমার ক্যোয়ারী রয়েছে যাতে আমি একটি ব্যাপ্তি দেই এবং তারপরে সেই ব্যাপ্তির সর্বোচ্চ মানটি ফিরে আসতে হবে। উদাহরণ স্বরূপ:

array[]={23,17,9,45,78,2,4,6,90,1};
query(both inclusive): 2 6
answer: 78

কোন রেঞ্জ থেকে সর্বাধিক মান পুনরুদ্ধার করতে আমি কোন অ্যালগরিদম বা ডেটা কাঠামো তৈরি করি। (অনেক প্রশ্ন আছে)

সম্পাদনা: এটি প্রকৃত সমস্যার একটি সাধারণ সংস্করণ। আমার কাছে অ্যারের আকার 100000 এবং 100000 পর্যন্ত প্রশ্নের সংখ্যা থাকতে পারে So সুতরাং আমি অবশ্যই কিছু প্রিপ্রোসেসিং প্রয়োজন যা দ্রুত জিজ্ঞাসার প্রতিক্রিয়াটি সহজতর করবে।


5
কেন এটি অরসোর্টেড? বাছাই করা হলে সমস্যাটি তুচ্ছ, সুতরাং সুস্পষ্ট পদ্ধতিকে এটি বাছাই করা।

1
@ ডেলান কিছু অতিরিক্ত প্রক্রিয়া ছাড়াই, আপনি অনুসন্ধানের হারের মধ্যে কোন মানটি মূলত ছিল তা হারিয়ে ফেলেন ...
থিজ ভ্যান ডায়ান

আপনার সম্পূর্ণ সমস্যা নির্দিষ্ট করুন। যদি এই জ্ঞান (বা অন্য কোনও তথ্য) বিষয়টি বিবেচনা করে তবে সমাধানের ক্ষেত্রে এটির কারণটি জানা উচিত।

1
আমি কি কিছু মিস করছি, বা এটি কেবল 2 থেকে 6 এর মধ্যে আইটেম পরিদর্শন করার এবং সেই উপাদানগুলির সর্বাধিক মান সন্ধান করার বিষয়?
blrfl

@ ব্লারফ্লাল: আমি মনে করি না যে আপনি অনেকগুলি অনুসন্ধানের অংশটি ব্যতীত আপনার কোনও কিছুই মিস করছেন । এটি এমন একটি কাঠামো তৈরির কোনও বিন্দু যা ক্রমগুলি সিক্যুয়াল অনুসন্ধানের চেয়ে যথেষ্ট সস্তা করে তোলে কিনা তা সত্যই স্পষ্ট নয়। (যদিও এই ধারণাটি না হলে এখানে প্রশ্ন জিজ্ঞাসা করার তেমন কোনও অর্থ হবে না))
মাইক শেরিল 'ক্যাট রিক্যাল'

উত্তর:


14

আমি মনে করি আপনি এক ধরণের বাইনারি গাছ তৈরি করতে পারেন যেখানে প্রতিটি নোড তার শিশুদের সর্বাধিক মান উপস্থাপন করে:

            78           
     45            78     
  23    45     78      6  
23 17  9 45   78 2    4 6   

তারপরে আপনার অনুসন্ধানের সীমাতে সর্বাধিক মান সন্ধান করার জন্য আপনাকে কোন নোডকে ন্যূনতমভাবে পরীক্ষা করতে হবে তা নির্ধারণের জন্য একটি উপায় অনুসন্ধান করতে হবে। এই উদাহরণস্বরূপ, সূচক পরিসরে সর্বাধিক মান পেতে [2, 6](সমেত) আপনার max(45, 78, 4)পরিবর্তে থাকতে হবে max(9, 45, 78, 2, 4)। গাছ বাড়ার সাথে সাথে লাভ আরও বাড়বে।


1
এটি কাজ করার জন্য, আপনার উদাহরণ গাছ থেকে তথ্য নেই: প্রতিটি অভ্যন্তরীণ নোডের সর্বাধিক এবং শিশু নোডের মোট সংখ্যা উভয়ই থাকতে হবে। অন্যথায় অনুসন্ধানের জানার কোনও উপায় নেই (উদাহরণস্বরূপ) এটির সমস্ত বাচ্চাদের 78(এবং এড়িয়ে যাওয়া 2) দিকে তাকাতে হবে না , কারণ এটি সমস্তই জানেন 6যে সূচকটি সেই সাবট্রিতে রয়েছে ree
ইজকাটা 4'13

অন্যথায়, +1 হিসাবে আমি এটি বরং উদ্ভাবক বলে মনে করি
ইজকাটা

+1: লগ (এন) সময়ে একটি তালিকার সাবরেঞ্জগুলি সম্পর্কে প্রশ্নের জবাব দেওয়ার জন্য এটি একটি শক্তিশালী কৌশল, মূল নোডের যে পরিমাণ ব্যবহারযোগ্য ব্যবহারের ক্ষেত্রে বাচ্চাদের ডেটা থেকে ধ্রুব সময়ে গণনা করা যায়।
কেভিন ক্লাইনে

এই ধারণাটি দুর্দান্ত। এটি ও (লগইন) ক্যোয়ারির সময় দেয়। আমার মনে হয় @ ইজকাটাও খুব ভাল একটা বিষয় দিয়েছে। বাম এবং ডান রেঞ্জের কভারগুলি সম্পর্কিত তথ্য সহ আমরা গাছের নোডকে বাড়িয়ে তুলতে পারি। সুতরাং একটি পরিসীমা দেওয়া, এটি কীভাবে সমস্যাটিকে দুটি ভাগে ভাগ করতে পারে তা জানে। স্থান অনুসারে, সমস্ত তথ্য পাতার স্তরে সংরক্ষণ করা হয়। সুতরাং এটিতে 2 * N স্থান প্রয়োজন যা সঞ্চয় করতে ও (এন) হয়। আমি জানি না সেগমেন্ট গাছ কী, তবে সেগমেন্ট গাছের পেছনে এই ধারণাটি কি?
কে

এবং প্রাক প্রসেসিংয়ের ক্ষেত্রে, গাছটি তৈরি করতে ও (এন) লাগে।
কে

2

Ngoaho91 এর উত্তর পরিপূরক।

এই সমস্যাটি সমাধানের সর্বোত্তম উপায় হ'ল সেগমেন্ট ট্রি ডেটা স্ট্রাকচার using এটি আপনাকে ও (লগ (এন)) এ এই জাতীয় প্রশ্নের উত্তর দেওয়ার অনুমতি দেয়, এর অর্থ আপনার অ্যালগোরিদমের মোট জটিলতা হবে ও (কিউ লগন) যেখানে প্রশ্নাবলীর সংখ্যা। আপনি যদি নিষ্পাপ অ্যালগরিদম ব্যবহার করেন তবে মোট জটিলতা হবেন O (Q n) যা স্পষ্টতই ধীর।

সেগমেন্ট গাছের ব্যবহারের ক্ষেত্রে একটি অপূর্ণতা রয়েছে। এটি প্রচুর স্মৃতি গ্রহণ করে তবে আপনি গতির চেয়ে স্মৃতি সম্পর্কে কম সময় যত্নশীল হন।

আমি এই ডিএস দ্বারা ব্যবহৃত অ্যালগরিদম সংক্ষেপে বর্ণনা করব:

সেগমেন্ট ট্রিটি বাইনারি অনুসন্ধান গাছের কেবল একটি বিশেষ কেস, যেখানে প্রতিটি নোড এটি নির্ধারিত রেঞ্জের মান ধারণ করে। মূল নোড, [0, n] এর সীমা নির্ধারিত হয়। বাম সন্তানের জন্য [0, (0 + n) / 2] এবং ডান সন্তান [(0 + n) / 2 + 1, n] সীমা নির্ধারণ করা হয়েছে। এভাবে গাছ তৈরি হবে।

গাছ তৈরি করুন :

/*
    A[] -> array of original values
    tree[] -> Segment Tree Data Structure.
    node -> the node we are actually in: remember left child is 2*node, right child is 2*node+1
    a, b -> The limits of the actual array. This is used because we are dealing
                with a recursive function.
*/

int tree[SIZE];

void build_tree(vector<int> A, int node, int a, int b) {
    if (a == b) { // We get to a simple element
        tree[node] = A[a]; // This node stores the only value
    }
    else {
        int leftChild, rightChild, middle;
        leftChild = 2*node;
        rightChild = 2*node+1; // Or leftChild+1
        middle = (a+b) / 2;
        build_tree(A, leftChild, a, middle); // Recursively build the tree in the left child
        build_tree(A, rightChild, middle+1, b); // Recursively build the tree in the right child

        tree[node] = max(tree[leftChild], tree[rightChild]); // The Value of the actual node, 
                                                            //is the max of both of the children.
    }
}

প্রশ্ন গাছ

int query(int node, int a, int b, int p, int q) {
    if (b < p || a > q) // The actual range is outside this range
        return -INF; // Return a negative big number. Can you figure out why?
    else if (p >= a && b >= q) // Query inside the range
        return tree[node];
    int l, r, m;
    l = 2*node;
    r = l+1;
    m = (a+b) / 2;
    return max(query(l, a, m, p, q), query(r, m+1, b, p, q)); // Return the max of querying both children.
}

আপনার যদি আরও ব্যাখ্যা দরকার হয় তবে আমাকে জানান।

বিটিডাব্লু, সেগমেন্ট ট্রি একটি একক উপাদান বা ও (লগ এন) এ উপাদানগুলির একটি ব্যাপ্তির আপডেটও সমর্থন করে


গাছ ভর্তি করার জটিলতা কী?
পিটার বি

আপনাকে সমস্ত উপাদানগুলির মধ্য দিয়ে যেতে হবে এবং O(log(n))প্রতিটি উপাদানকে গাছে যুক্ত করতে হবে। অতএব, মোট জটিলতা হ'লO(nlog(n))
আন্দ্রে

1

নীচের হিসাবে ও (এন) সময়ে সেরা অ্যালগরিদম হবে শুরু করা যাক, শেষ সীমার সীমা সূচক হতে হবে

int findMax(int[] a, start, end) {
   max = Integer.MIN; // initialize to minimum Integer

   for(int i=start; i <= end; i++) 
      if ( a[i] > max )
         max = a[i];

   return max; 
}

4
-1 কেবল অ্যালগরিদম পুনরাবৃত্তি করার জন্য ওপি উন্নত করার চেষ্টা করছিল।
কেভিন ক্লাইন

1
বর্ণিত সমস্যার সমাধান পোস্ট করার জন্য +1। এটির একমাত্র উপায় এটি যদি আপনার কাছে অ্যারে থাকে এবং সীমাটি কোন অগ্রাধিকার হতে চলেছে তা জানেন না । (যদিও আমি লুপটি শুরু maxকরতে a[i]এবং fori+1
এটিকে

@ কেভিঙ্কলাইন এটি কেবল বিশ্রাম নয় - এটি "হ্যাঁ, আপনার কাছে ইতিমধ্যে এই কাজটির জন্য সেরা অ্যালগরিদম রয়েছে" বলছেন, একটি সামান্য উন্নতি (ঝাঁপুন start, থামুন end)। আর আমি একমত, এই হল একটি এক-কালীন লুকআপ জন্য শ্রেষ্ঠ। @ থিজসওয়ানডিয়েনের উত্তরটি কেবল তখনই আরও ভাল তবে যদি অনুসন্ধানটি একাধিকবার ঘটতে চলেছে, যেহেতু প্রাথমিকভাবে সেট আপ করতে এটি বেশি সময় নেয়।
ইজকাটা

মঞ্জুর, এই উত্তর পোস্ট করার সময়, প্রশ্নটিতে সম্পাদনাটি নিশ্চিত করে না যে তিনি একই ডেটা নিয়ে অনেকগুলি প্রশ্ন করবেন doing
ইজকাটা

1

বাইনারি ট্রি / সেগমেন্ট ট্রি-ভিত্তিক সমাধানগুলি সত্যই সঠিক দিকে নির্দেশ করছে। কেউ আপত্তি করতে পারেন যে তাদের অতিরিক্ত মেমরির প্রয়োজন, তবে। এই সমস্যার দুটি সমাধান রয়েছে:

  1. বাইনারি গাছের পরিবর্তে একটি অন্তর্নিহিত ডেটা কাঠামো ব্যবহার করুন
  2. বাইনারি গাছের পরিবর্তে একটি এম-আরি গাছ ব্যবহার করুন

প্রথম বিষয়টি হ'ল গাছটি অত্যন্ত কাঠামোগত, আপনি নোড, বাম এবং ডান পয়েন্টার, বিরতি ইত্যাদির সাহায্যে গাছকে উপস্থাপন করার পরিবর্তে গাছটিকে স্পষ্টভাবে সংজ্ঞায়িত করতে একটি স্তূপের মতো কাঠামো ব্যবহার করতে পারেন That যা মূলত অনেক স্মৃতি সঞ্চয় করে কোনও পারফরম্যান্স হিট না - আপনাকে আরও কিছু পয়েন্টার গাণিতিক সম্পাদন করতে হবে।

দ্বিতীয় বিষয়টি হ'ল, মূল্যায়নের সময় আরও কিছু বেশি কাজের ব্যয়ে আপনি বাইনারি গাছের পরিবর্তে এম-আরি গাছ ব্যবহার করতে পারেন। উদাহরণস্বরূপ আপনি যদি 3-আরি গাছ ব্যবহার করেন তবে আপনি একবারে সর্বাধিক 3 টি উপাদান, তারপরে একবারে 9 টি উপাদান, তারপরে 27 ইত্যাদি গণনা করতে পারেন তবে অতিরিক্ত স্টোরেজটি N / (M-1) হয় - আপনি পারেন জ্যামিতিক সিরিজের সূত্রটি ব্যবহার করে প্রমাণ করুন। উদাহরণস্বরূপ, আপনি যদি এম = 11 চয়ন করেন তবে আপনার বাইনারি ট্রি পদ্ধতির 1/10 তম স্টোরেজ প্রয়োজন।

পাইথনে এই নিষ্পাপ এবং অনুকূলিতকরণগুলি একই ফলাফল দেয় তা আপনি যাচাই করতে পারেন:

class RangeQuerier(object):
    #The naive way
    def __init__(self):
        pass

    def set_array(self,arr):
        #Set, and preprocess
        self.arr = arr

    def query(self,l,r):
        try:
            return max(self.arr[l:r])
        except ValueError:
            return None

বনাম

class RangeQuerierMultiLevel(object):
    def __init__(self):
        self.arrs = []
        self.sub_factor = 3
        self.len_ = 0

    def set_array(self,arr):
        #Set, and preprocess
        tgt = arr
        self.len_ = len(tgt)
        self.arrs.append(arr)
        while len(tgt) > 1:
            tgt = self.maxify_one_array(tgt)
            self.arrs.append(tgt)

    def maxify_one_array(self,arr):
        sub_arr = []
        themax = float('-inf')
        for i,el in enumerate(arr):
            themax = max(el,themax)
            if i % self.sub_factor == self.sub_factor - 1:
                sub_arr.append(themax)
                themax = float('-inf')
        return sub_arr

    def query(self,l,r,level=None):
        if level is None:
            level = len(self.arrs)-1

        if r <= l:
            return None

        int_size = self.sub_factor ** level 

        lhs,mid,rhs = (float('-inf'),float('-inf'),float('-inf'))

        #Check if there's an imperfect match on the left hand side
        if l % int_size != 0:
            lnew = int(ceil(l/float(int_size)))*int_size
            lhs = self.query(l,min(lnew,r),level-1)
            l = lnew
        #Check if there's an imperfect match on the right hand side
        if r % int_size != 0:
            rnew = int(floor(r/float(int_size)))*int_size
            rhs = self.query(max(rnew,l),r,level-1)
            r = rnew

        if r > l:
            #Handle the middle elements
            mid = max(self.arrs[level][l/int_size:r/int_size])
        return max(max(lhs,mid),rhs)

0

"সেগমেন্ট ট্রি" ডেটা স্ট্রাকচার চেষ্টা করে দেখুন
2 টি ধাপে
বিল্ড_ট্রি () ও (এন)
ক্যোয়ারী (ইন মিনিট, ইনট ম্যাক্স) ও (নলগন)

http://en.wikipedia.org/wiki/Segment_tree

সম্পাদনা:

আপনি ছেলেরা শুধু আমি পাঠানো উইকি পড়েন না!

এই অ্যালগরিদমটি হ'ল:
আপনি গাছ তৈরির জন্য অ্যারেটিকে 1 বার অতিক্রম করেন। ও (এন)
- পরবর্তী 100000000+ বার আপনি অ্যারের কোনও অংশের সর্বাধিক জানতে চান, কেবল ক্যোয়ারী ফাংশনটিতে কল করুন। হে (logn) জন্য প্রতি ক্যোয়ারী
- C ++ এখানে বাস্তবায়ন geeksforgeeks.org/segment-tree-set-1-range-minimum-query/
পুরাতন অ্যালগরিদম হল:
যে প্রশ্নের সাথে, শুধু নির্বাচিত এলাকার তর্ক এবং খুঁজে।

সুতরাং, আপনি যদি একবার প্রক্রিয়া করতে এই অ্যালগরিদম ব্যবহার করতে চান, ঠিক আছে, এটি পুরানো উপায়ের চেয়ে ধীর। তবে যদি আপনি বিপুল সংখ্যক ক্যোয়ারী (বিলিয়ন) প্রক্রিয়াকরণ করতে চান তবে এটি খুব দক্ষ আপনি পরীক্ষার

লাইন 1: 50000 এলোমেলো সংখ্যা 0-1000000 থেকে '(স্পেস)' (এটি অ্যারে)
লাইন দ্বারা বিভক্ত করার জন্য এই জাতীয় পাঠ্য ফাইল তৈরি করতে পারবেন 2: 2 এলোমেলো সংখ্যা 1 থেকে 50000, '(স্পেস)' দ্বারা বিভক্ত (এটি ক্যোয়ারী)
...
লাইন 200000: লাইন 2 পছন্দ করে, এটিও এলোমেলো ক্যোয়ারী

এটি উদাহরণস্বরূপ সমস্যা, দুঃখিত তবে এটি ভিয়েতনামিতে
http://vn.spoj.com/problems/NKLINEUP/
আপনি যদি পুরানো উপায়ে সমাধান করেন তবে আপনি কখনই পাস করবেন না।


3
আমি প্রাসঙ্গিক মনে করি না। একটি অন্তর্বর্তী গাছ বিরতি রাখে, পূর্ণসংখ্যা নয় এবং তারা যে ক্রিয়াকলাপের অনুমতি দেয় সেগুলি ওপি যা বলেছে তেমন কিছুই দেখায় না। আপনি অবশ্যই সমস্ত সম্ভাব্য বিরতি তৈরি করতে এবং সেগুলি একটি বিরল গাছে সংরক্ষণ করতে পারতেন, কিন্তু (1) তাদের মধ্যে অনেকগুলি তাত্পর্যপূর্ণভাবে রয়েছে, সুতরাং এটি স্কেল হয় না, এবং (২) ক্রিয়াকলাপগুলি এখনও ওপি এর মতো দেখাচ্ছে না জিজ্ঞাসা করা.

আমার ভুল, আমি বলতে চাই সেগমেন্ট গাছ, অন্তরবৃক্ষ নয়।
ngoaho91

আকর্ষণীয়, আমি মনে করি আমি এই গাছটি পেরিয়ে কখনও আসিনি! আইআইইউসি এর জন্য এখনও সমস্ত সম্ভাব্য অন্তর সংরক্ষণের প্রয়োজন। আমি মনে করি সেগুলির মধ্যে ও (এন ^ 2) রয়েছে, যা ব্যয়বহুল। (এছাড়াও, কে ফলাফলের জন্য ও (লগ এন + কে) হওয়া উচিত নয় ?

হ্যাঁ, অকার্যকর বিল্ড_ট্রি () অবশ্যই অ্যারে পার হতে হবে। এবং প্রতিটি নোডের জন্য সর্বাধিক (বা ন্যূনতম) মান সঞ্চয় করুন। তবে অনেক ক্ষেত্রে গতির চেয়ে মেমরির ব্যয় গুরুত্বপূর্ণ নয়।
ngoaho91

2
O(n)তরুন_তাল্যাংকের উত্তরে বর্ণিত হিসাবে অ্যারের সরল অনুসন্ধানের চেয়ে এটি আর দ্রুততর আমি তা কল্পনা করতে পারি না । প্রথম প্রবৃত্তিটি O(log n + k)এটির চেয়ে দ্রুত O(n), তবে এটি O(log n + k)কেবল সাব-অ্যারের পুনরুদ্ধার - O(1)শুরু এবং শেষের পয়েন্টগুলি সরবরাহ করে অ্যারে অ্যাক্সেসের সমতুল্য । আপনার সর্বাধিক সন্ধানের জন্য এটিকে অনুসরণ করতে হবে।
ইজকাটা

0

স্পার সারণী নামক ডেটা স্ট্রাকচার ব্যবহার করে আপনি প্রতিটি ক্যোয়ারিতে ও (1) অর্জন করতে পারেন (ও (এন লগ এন) নির্মাণের সাথে)। 2 এর প্রতিটি পাওয়ারের জন্য আসুন এই দৈর্ঘ্যের প্রতিটি বিভাগের জন্য সর্বাধিক সংরক্ষণ করুন। এখন প্রদত্ত বিভাগ [l, r) আপনি যথাযথ কে এর জন্য [l + 2 ^ k) এবং [r-2 ^ k, r) সর্বাধিক সর্বাধিক পাবেন। তারা ওভারল্যাপ করে তবে এটি ঠিক আছে

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.