একটি মিলিয়ন সংখ্যার একটি স্ট্রিং দেওয়া, সমস্ত পুনরাবৃত্তি 3 সংখ্যার সংখ্যাটি ফিরিয়ে দিন


137

কয়েক মাস আগে নিউ ইয়র্কের একটি হেজ ফান্ড সংস্থার সাথে আমার একটি সাক্ষাত্কার হয়েছিল এবং দুর্ভাগ্যক্রমে, আমি ডেটা / সফটওয়্যার ইঞ্জিনিয়ার হিসাবে ইন্টার্নশিপের অফার পাইনি। (তারা সমাধানটি পাইথনে থাকার জন্যও বলেছিল।)

প্রথম সাক্ষাত্কারের সমস্যাটি নিয়ে আমি খুব খারাপ হয়েছি ...

প্রশ্ন: মিলিয়ন সংখ্যার একটি স্ট্রিং দেওয়া (উদাহরণস্বরূপ পাই), একটি ফাংশন / প্রোগ্রাম লিখুন যা সমস্ত পুনরাবৃত্তি 3 ডিজিট সংখ্যা এবং 1 এর চেয়ে বেশি পুনরাবৃত্তির সংখ্যা দেয়

উদাহরণস্বরূপ: যদি স্ট্রিংটি ছিল: 123412345123456তবে ফাংশন / প্রোগ্রামটি ফিরে আসবে:

123 - 3 times
234 - 3 times
345 - 2 times

আমি সাক্ষাত্কারে ব্যর্থ হওয়ার পরে তারা আমাকে সমাধানটি দেয় নি, তবে তারা আমাকে বলেছিল যে সমস্ত সম্ভাব্য ফলাফলের মধ্যে সমাধানের জন্য সময় জটিলতা 1000 ধ্রুবক ছিল:

000 -> 999

এখন যেহেতু আমি এটি নিয়ে ভাবছি, আমি মনে করি না ধ্রুবক সময় অ্যালগরিদম নিয়ে আসা সম্ভব। তাই কি?


68
যদি তারা মনে করেন যে সমাধানটি 1000 এর ধ্রুবক, তবে এটি আমাকে ভাবায় যে তারা তিন-অঙ্কের সমস্ত সংখ্যা তৈরি করেছিলেন এবং তারপরে রেজেক্স তাদের অনুসন্ধান করেছিলেন। লোকেদের পক্ষে এটি ভাবা খুব সাধারণ যে তারা যে লেখাগুলি লিখে / দেখে না তারা "নিখরচায়" operations আমি পুরোপুরি নিশ্চিত যে এটি স্ট্রিংয়ের দৈর্ঘ্যের লিনিয়ার হবে।
মাইপটেলিয়ন

54
নিতপিকভাবে, ইনপুট আকারটি যদি একটি ধ্রুবক থাকে তবে প্রতিটি অ্যালগরিদম ধ্রুবক সময় ;-)
পেলো এবারম্যান

34
ধ্রুব 1000 কি ? (সংযোজন? হাতি?)
ilkkachu

31
ঠিক আছে, যদি স্ট্রিংয়ের দৈর্ঘ্য ধ্রুবক হয় (1 এম) এবং স্তর / সংখ্যা দৈর্ঘ্য ধ্রুবক (3) হয় তবে প্রযুক্তিগতভাবে প্রতিটি সমাধান স্থির সময় হয় ...
কেভিন

8
They did not give me the solution after I failed the interview, but they did tell me that the time complexity for the solution was constant of 1000 since all the possible outcomes are between: 000 --> 999 এটি সম্ভবত আসল পরীক্ষা ছিল। আপনি কেন তাদের পক্ষে প্রমাণ করতে পারছেন যে কেন এটি সম্ভব নয় এবং সঠিক ন্যূনতম সময়ের জটিলতা তাদের দেখান।
জেমস 15

উত্তর:


168

আপনি হালকাভাবে নামলেন, আপনি সম্ভবত হেজ ফান্ডের জন্য কাজ করতে চান না যেখানে কোয়ান্ট্যান্ট বেসিক অ্যালগরিদমগুলি বুঝতে পারে না :-)

নেই কোন একটি ইচ্ছামত আকারের ডাটা স্ট্রাকচার প্রক্রিয়া উপায় O(1), যদি এই ক্ষেত্রে হিসাবে, আপনি একবার অন্তত প্রতিটি উপাদান যেতে হবে। সেরা আপনি আশা করতে পারেন O(n)এই ক্ষেত্রে, যেখানে nস্ট্রিং এর দৈর্ঘ্য হল।

যদিও, একটি সরাইয়া হিসাবে, একটি নামমাত্র O(n)অ্যালগরিদম হবে হতে O(1)তাই হয়, টেকনিক্যালি একটি নির্দিষ্ট ইনপুট আকার জন্য, তারা এখানে সঠিক ছিল। যাইহোক, এটি সাধারণত জটিলতা বিশ্লেষণগুলি কীভাবে ব্যবহার করে তা নয়।

এটি আমার কাছে মনে হচ্ছে আপনি তাদের বিভিন্ন উপায়ে মুগ্ধ করতে পারতেন।

প্রথমে তাদের জানিয়ে দিয়ে যে এটি করা সম্ভব নয়O(1) , যদি না আপনি উপরে বর্ণিত "সন্দেহভাজন" যুক্তি ব্যবহার করেন।

দ্বিতীয়ত, পাইথোনিক কোড সরবরাহ করে আপনার অভিজাত দক্ষতা দেখিয়ে যেমন:

inpStr = '123412345123456'

# O(1) array creation.
freq = [0] * 1000

# O(n) string processing.
for val in [int(inpStr[pos:pos+3]) for pos in range(len(inpStr) - 2)]:
    freq[val] += 1

# O(1) output of relevant array values.
print ([(num, freq[num]) for num in range(1000) if freq[num] > 1])

এই ফলাফলগুলি:

[(123, 3), (234, 3), (345, 2)]

যদিও আপনি অবশ্যই অবশ্যই আকাঙ্ক্ষিত যে কোনও কিছুতে আউটপুট ফর্ম্যাটটি পরিবর্তন করতে পারেন।

এবং অবশেষে, তাদের বলার মাধ্যমে সমাধানের সাথে অবশ্যই কোনও সমস্যা নেইO(n) , কারণ উপরের কোডটি অর্ধ সেকেন্ডের নীচে দশ মিলিয়নের অঙ্কের স্ট্রিংয়ের ফলাফল সরবরাহ করে। এটি 10,000 মিলিয়ন-অক্ষরের স্ট্রিংটিতে 3.5 সেকেন্ড এবং 100,000,000-চরিত্রের ক্ষেত্রে 36 সেকেন্ড সময় নেয় বলে মনে হয় এটি বেশ লাইনগতভাবে স্কেল বলে মনে হচ্ছে।

এবং, তাদের যদি এর চেয়ে আরও ভাল প্রয়োজন হয় তবে এই ধরণের জিনিসগুলির সমান্তরাল করার উপায় রয়েছে যা এটির গতি বাড়িয়ে তুলতে পারে।

জিআইএল-এর কারণে অবশ্যই একক পাইথন দোভাষীর মধ্যে নয় , আপনি স্ট্রিংটিকে এমন কিছুতে বিভক্ত করতে পারেন ( vvসীমানা অঞ্চলের সঠিক প্রক্রিয়াকরণের অনুমতি দেওয়ার জন্য নির্দেশিত ওভারল্যাপের প্রয়োজন):

    vv
123412  vv
    123451
        5123456

এগুলি আপনি আলাদা কর্মী তৈরি করতে এবং ফলাফলগুলি পরে একত্রিত করতে পারেন।

ইনপুট বিভক্তকরণ এবং আউটপুট সংমিশ্রণ সম্ভবত ছোট স্ট্রিং (এবং সম্ভবত মিলিয়ন-অঙ্কের স্ট্রিং) দিয়ে যে কোনও সঞ্চয়কে জলাবদ্ধ করতে পারে তবে, আরও বড় ডেটা সেটগুলির জন্য, এটি ভালভাবে পার্থক্য করতে পারে। অবশ্যই "পরিমাপ, অনুমান করবেন না" এর আমার সাধারণ মন্ত্রটি অবশ্যই এখানে প্রয়োগ হয়।


এই মন্ত্রটি অন্যান্য সম্ভাবনার ক্ষেত্রেও প্রযোজ্য যেমন পাইথনকে পুরোপুরি বাইপাস করা এবং একটি ভিন্ন ভাষা ব্যবহার করা যা দ্রুত হতে পারে।

উদাহরণস্বরূপ, নিম্নলিখিত সি কোড, পূর্ববর্তী পাইথন কোডের মতো একই হার্ডওয়্যারে চলমান, 0.6 সেকেন্ডে একশ মিলিয়ন অঙ্ক পরিচালনা করে , প্রায় একই সময় পাইথন কোডটি এক মিলিয়ন প্রক্রিয়াজাত করে । অন্য কথায়, অনেক দ্রুত:

#include <stdio.h>
#include <string.h>

int main(void) {
    static char inpStr[100000000+1];
    static int freq[1000];

    // Set up test data.

    memset(inpStr, '1', sizeof(inpStr));
    inpStr[sizeof(inpStr)-1] = '\0';

    // Need at least three digits to do anything useful.

    if (strlen(inpStr) <= 2) return 0;

    // Get initial feed from first two digits, process others.

    int val = (inpStr[0] - '0') * 10 + inpStr[1] - '0';
    char *inpPtr = &(inpStr[2]);
    while (*inpPtr != '\0') {
        // Remove hundreds, add next digit as units, adjust table.

        val = (val % 100) * 10 + *inpPtr++ - '0';
        freq[val]++;
    }

    // Output (relevant part of) table.

    for (int i = 0; i < 1000; ++i)
        if (freq[i] > 1)
            printf("%3d -> %d\n", i, freq[i]);

    return 0;
}

19
এই "স্থির ইনপুট আকার" সত্যিই খারাপ কৌতুক বলে মনে হয় ইন্টারভিউয়ার বা ইন্টারভিউওয়ালি পায় নি। প্রতিটি আলগোরিদিম হয়ে O(1)হয় nনির্দিষ্ট অথবা bounded হয়।
এরিক ডুমিনিল

5
তাদের যদি এর চেয়ে আরও ভাল প্রয়োজন হয় তবে তারা পাইথনটি ব্যবহার করবেন না, কমপক্ষে নির্দিষ্ট অ্যালগরিদমের জন্য।
সেবাস্তিয়ান রেডল

3
@ ইজজক্যাশ কারণ সমান্তরাল পদ্ধতির চেষ্টা করার সময় পয়েন্টগুলিতে স্ট্রিং "ভেঙে" ফেলা হচ্ছে সেখানে ওভারল্যাপ থাকতে পারে। যেহেতু আপনি 3-সংখ্যার গোষ্ঠী সন্ধান করছেন, -2 উভয় সমান্তরাল গ্রুপিংয়ের চেকটিকে কোনও সম্ভাব্য বৈধ ম্যাচটি মিস করতে দেয় না
কোড_ড্রেড

5
@ ইজজক্যাশ এটি সমান্তরাল প্রোগ্রামিং জ্ঞানের অভাব নয়। দৈর্ঘ্যের একটি স্ট্রিং বিবেচনা করুন N। যদি আপনি এটি অবস্থানের দুটি ভাগে বিভক্ত করেন তবে N/2আপনার এখনও অ্যাকাউন্টটির প্রয়োজন যে আপনি "সীমান্তে" শেষে string1এবং এর শুরুতে একটি বৈধ 3-অঙ্কের ম্যাচটি মিস করতে পারেন string2। সুতরাং, আপনার মধ্যে ( string1[N/2-2]এবং string2[2]শূন্য-ভিত্তিক সূচক ব্যবহার করে) ম্যাচগুলি পরীক্ষা করা দরকার That's এটাই ধারণা।
কোড_ড্রেড

1
দীর্ঘতর ডিজিট-সিকোয়েন্স সহ, একটি স্লাইডিং উইন্ডো দিয়ে পূর্ণসংখ্যায় রূপান্তরটি অনুকূলকরণ থেকে কিছু অর্জন করতে হবে যা আপনাকে সর্বোচ্চ সংখ্যায় ফেলে এবং একটি নতুন অঙ্ক যুক্ত করতে দেয়। (পাইথন ওভারহেড সম্ভবত এটি মেরে ফেলবে, সুতরাং এটি কেবল সি বা অন্যান্য নিম্ন-স্তরের বাস্তবায়নের ক্ষেত্রে প্রযোজ্য)। val -= 100 * (d[i]-'0');নেতৃস্থানীয় অঙ্ক বাদ দিতে। val = 10*val + d[i+2]-'0'একটি নতুন সর্বনিম্ন-উল্লেখযোগ্য অঙ্ক (সাধারণ স্ট্রিং-> পূর্ণসংখ্যা পার্সিং) সংগ্রহ করতে accum val % 100সম্ভবত অ-ভয়ঙ্কর, তবে কেবল তখনই 100যদি একটি সংকলন-সময় ধ্রুবক থাকে তবে এটি আসল এইচডাব্লু বিভাজনটি ব্যবহার করে না।
পিটার কর্ডস

78

অবিচ্ছিন্ন সময় সম্ভব নয়। কমপক্ষে একবারে সমস্ত 1 মিলিয়ন অঙ্কের দিকে নজর দেওয়া দরকার, সুতরাং এটি ও (এন) এর একটি সময়ের জটিলতা, যেখানে এই ক্ষেত্রে n = 1 মিলিয়ন।

একটি সাধারণ ও (এন) সমাধানের জন্য, 1000 আকারের একটি অ্যারে তৈরি করুন যা প্রতিটি সম্ভাব্য 3 ডিজিটের সংখ্যার সংখ্যার প্রতিনিধিত্ব করে। একটি হিস্টোগ্রাম তৈরি করতে প্রতিটি সূচি == 0, শেষ সূচক == 999997 এবং বর্ধিত অ্যারে [3 ডিজিট সংখ্যা] একবারে অগ্রিম করুন (প্রতিটি সম্ভাব্য 3 সংখ্যার সংখ্যার সংখ্যার সংখ্যা)। তারপরে অ্যারেটির সামগ্রীকে গণনা> 1 দিয়ে আউটপুট করুন।


26
@ ইজজক্যাশ - হ্যাঁ একটি অভিধান কাজ করবে তবে এটির দরকার নেই। সমস্ত সম্ভাব্য "কীগুলি" আগাম হিসাবে জানা যায়, 0 থেকে 999 এর মধ্যে সীমাবদ্ধ over একটি সূচকে ডিজিট স্ট্রিং এবং তারপরে অ্যারে অ্যাক্সেস করতে সূচকটি ব্যবহার করুন।
rcgldr

4
আপনি যদি সংখ্যাসূচক কৌশলগুলি চান তবে আপনি বিসিডিতে গিয়ে তিনটি সংখ্যা 12 বিটে সংরক্ষণ করার সিদ্ধান্ত নিতে পারেন। এবং 4 টি বিটকে মাস্কিং করে ASCII সংখ্যাগুলি ডিকোড করুন। তবে সেই x-'0'প্যাটার্নটি পাইথনে বৈধ নয়, এটি একটি সি-ইসম (যেখানে অক্ষরগুলি পূর্ণসংখ্যা হয়)।
ইয়ান ভার্নিয়ার

5
@ লরেনপেকটেল: পাইথনে অভিধানের অনুসন্ধানগুলি সত্যিই দ্রুত। মঞ্জুর, অ্যারে অ্যাক্সেস আরও দ্রুত, সুতরাং আমরা যদি প্রথম থেকেই পূর্ণসংখ্যার সাথে কাজ করতাম তবে আপনি ঠিকই থাকতেন। তবে, এই ক্ষেত্রে, আমাদের কাছে 3-দৈর্ঘ্যের স্ট্রিং রয়েছে, যা আমরা প্রথমে পূর্ণসংখ্যায় রূপান্তর করতে হবে যদি আমরা সেগুলি অ্যারে ব্যবহার করতে চাই। এটি প্রথম যেটি প্রত্যাশা করতে পারে তার বিপরীতে দেখা যাচ্ছে, অভিধান অনুসন্ধানটি আসলে পূর্ণসংখ্যার রূপান্তর + অ্যারে অ্যাক্সেসের চেয়ে দ্রুত। অ্যারের সমাধান আসলে এই ক্ষেত্রে 50% ধীর।
আলেকসি তোড়হামো

2
আমি অনুমান করি যে কেউ যুক্তি দিতে পারে যে ইনপুট সংখ্যাটিতে সর্বদা 1 মিলিয়ন অঙ্ক থাকে তবে এর চেয়ে অ্যালগরিদম হ'ল (1), 1 মিলিয়ন ধ্রুবক ফ্যাক্টর সহ।
tobias_k

2
@ অ্যালেক্সি টোরহামো - যদি অ্যালগরিদমের জন্য বাস্তবায়নের তুলনামূলক গতি তুলনা করা লক্ষ্য হয় তবে আমি সি বা সি ++ এর মতো একটি traditionalতিহ্যবাহী ভাষা পছন্দ করবো, যেহেতু পাইথন উল্লেখযোগ্যভাবে ধীর এবং অন্য ভাষার তুলনায় পাইথনের তুলনায় ওভারহেডগুলি অনন্য বলে মনে হচ্ছে।
rcgldr

14

আমি নীচে দেওয়া উত্তরটির জন্য এক মিলিয়ন ছোট। কেবলমাত্র এই প্রত্যাশা করে যে আপনাকে কোনও বিরতি ছাড়াই সাক্ষাত্কারে সমাধানটি চালাতে সক্ষম হতে হবে, তারপরে নিম্নলিখিতটি দুটি সেকেন্ডেরও কম সময়ে কাজ করে এবং প্রয়োজনীয় ফলাফল দেয়:

from collections import Counter

def triple_counter(s):
    c = Counter(s[n-3: n] for n in range(3, len(s)))
    for tri, n in c.most_common():
        if n > 1:
            print('%s - %i times.' % (tri, n))
        else:
            break

if __name__ == '__main__':
    import random

    s = ''.join(random.choice('0123456789') for _ in range(1_000_000))
    triple_counter(s)

আশা করি সাক্ষাত্কারকারক স্ট্যান্ডার্ড লাইব্রেরি সংগ্রহের ব্যবহার খুঁজছেন।

সমান্তরাল সম্পাদন সংস্করণ

আমি আরও ব্যাখ্যা দিয়ে একটি ব্লগ পোস্ট লিখেছিলাম ।


এটি সূক্ষ্মভাবে কাজ করে এবং এটি দ্রুততম, ননপি সমাধান সমাধান বলে মনে হচ্ছে।
এরিক ডুমিনিল

3
@ এরিকডুমিনিল, আমি মনে করি না যে আপনার এখানে দ্রুততম সময় থাকার বিষয়ে চিন্তা করা উচিত, যখন বেশিরভাগ সমাধান দেওয়া আপনাকে বেশি বিলম্বিত করে না। পাইথন স্ট্যান্ডার্ড লাইব্রেরিটি আপনার কাছে ভালভাবে উপলব্ধি করে দেখানোর চেয়ে আরও ভাল এবং আমি মনে করব যে কোনও সাক্ষাত্কারের পরিস্থিতিতে রক্ষণাবেক্ষণযোগ্য কোডটি লিখতে পারেন। (যদি না ইন্টারভিউকারী সময় সমালোচনার উপর জোর দেয় তবে তারপরে কী ঘটে থাকে তা মূল্যায়ন করার আগে আপনার আসল সময়গুলির জন্য জিজ্ঞাসা করা উচিত)।
প্যাডি3118

1
আমরা 100% সম্মত। যদিও আমি নিশ্চিত নই যে কোনও উত্তর মোটেই প্রাসঙ্গিক কিনা যদি সাক্ষাত্কারকারী সত্যই মনে করে এটি করা সম্ভব O(1)
এরিক ডুমিনিল

1
যদি সাক্ষাত্কারকারী জোর দিয়েছিলেন যে এটি সময় সমালোচনামূলক ছিল, তবে এটির সীমাটি তা নিশ্চিত করার জন্য প্রোফাইল দেওয়ার পরে , এই বাধাটি মোকাবেলার জন্য কোনও সি মডিউল লেখার সময় আসতে পারে। আমার কাছে একটি স্ক্রিপ্ট রয়েছে যা এসি মডিউলটি ব্যবহার শুরু করার পরে পাইথন কোডের চেয়ে 84x উন্নতি দেখেছি।
টেম্পোরাল

হাই @ টেম্পোরাল ওল্ফ, আপনি যা বলেছিলেন তা আমি পড়েছি তখন ভেবেছিল যে আর একটি, দ্রুত এবং স্কেলযোগ্য সমাধান হতে পারে এটি একটি সমান্তরাল অ্যালগরিদমে পরিবর্তন করা যাতে এটি একটি কম্পিউট ফার্ম / ক্লাউডে অনেকগুলি প্রক্রিয়াতে চালিত হতে পারে। আপনাকে স্ট্রিংটিকে এন বিভাগে বিভক্ত করতে হবে; প্রতিটি বিভাগের শেষ অংশটি এর পরবর্তী বিভাগটি দিয়ে ওভারল্যাপিং করা। তারপরে প্রতিটি বিভাগকে স্বাধীনভাবে ট্রিপলগুলির জন্য স্ক্যান করা যেতে পারে, ত্রিগুণগুলি সংশ্লেষ করা যায়, এবং শেষের দিকে তিনটি চর ট্রিপল বাদে শেষ অংশটি বিয়োগ করা হত কারণ এটি দ্বিগুণ গণনা করা হত। আমার কাছে কোডটি রয়েছে এবং সম্ভবত এটি একটি ব্লগ পোস্টে পরিণত হবে ...
প্যাডি 3118

13

সাধারণ ও (এন) সমাধানটি হ'ল প্রতিটি 3-সংখ্যার সংখ্যা গণনা করা:

for nr in range(1000):
    cnt = text.count('%03d' % nr)
    if cnt > 1:
        print '%03d is found %d times' % (nr, cnt)

এটি সমস্ত 1 মিলিয়ন অঙ্ক 1000 বার অনুসন্ধান করবে।

অঙ্কগুলি কেবল একবারে ট্রান্স করা হচ্ছে:

counts = [0] * 1000
for idx in range(len(text)-2):
    counts[int(text[idx:idx+3])] += 1

for nr, cnt in enumerate(counts):
    if cnt > 1:
        print '%03d is found %d times' % (nr, cnt)

সময় দেখায় যে সূচকের একবারে পুনরাবৃত্তি করা ব্যবহারের চেয়ে দ্বিগুণ দ্রুত count


37
কোন কালো শুক্রবার ছাড় আছে text.count()?
এরিক ডুমিনিল

3
@ এরিকডুমিনিল আপনার কাছে একটি ভাল পয়েন্ট রয়েছে তবে যেহেতু text.countঅজগর-স্তরের ব্যাখ্যার সাথে লুপিংয়ের বিপরীতে উচ্চ-গতির সংকলিত ভাষায় (যেমন সি) করা হয়, হ্যাঁ একটি ছাড় রয়েছে।
1024

প্রতিটি সংখ্যা পৃথকভাবে গণনা করা খুব অদক্ষ তবে এটি একটি ধ্রুবক সময়, সুতরাং এখনও হে (এন)।
লরেন পেচটেল

11
আপনার প্রস্তাবিত বিকল্পটি countভুল, কারণ এটি ওভারল্যাপিং নিদর্শনগুলি গণনা করবে না। নোট করুন যে '111'.count('11') == 1আমরা কখন এটির আশা করব 2
Cireo

2
এছাড়াও, আপনার "সরল O(n)সমাধান" আসলে O(10**d * n)সঙ্গে dঅনুসন্ধান ডিজিটের নম্বর এবং nস্ট্রিং এর মোট দৈর্ঘ্য। দ্বিতীয়টি হ'ল O(n)সময় এবং O(10**d + n)স্থান।
এরিক ডুমিনিল

10

এখানে "sensকমত্য" ও (এন) অ্যালগরিদমের একটি নুমপি বাস্তবায়ন রয়েছে: সমস্ত ট্রিপল্ট এবং বিন হিসাবে আপনি যেতে পারেন। "385" বলার মুখোমুখি হয়ে বিনিংটি করা হয়, একটিতে বিনকে যোগ করে [3, 8, 5] যা ও (1) অপারেশন is বিন একটি 10x10x10ঘনক্ষেত্র মধ্যে সাজানো হয় । বিনিং পুরোপুরি ভেক্টরাইজড হওয়ায় কোডটিতে কোনও লুপ নেই।

def setup_data(n):
    import random
    digits = "0123456789"
    return dict(text = ''.join(random.choice(digits) for i in range(n)))

def f_np(text):
    # Get the data into NumPy
    import numpy as np
    a = np.frombuffer(bytes(text, 'utf8'), dtype=np.uint8) - ord('0')
    # Rolling triplets
    a3 = np.lib.stride_tricks.as_strided(a, (3, a.size-2), 2*a.strides)

    bins = np.zeros((10, 10, 10), dtype=int)
    # Next line performs O(n) binning
    np.add.at(bins, tuple(a3), 1)
    # Filtering is left as an exercise
    return bins.ravel()

def f_py(text):
    counts = [0] * 1000
    for idx in range(len(text)-2):
        counts[int(text[idx:idx+3])] += 1
    return counts

import numpy as np
import types
from timeit import timeit
for n in (10, 1000, 1000000):
    data = setup_data(n)
    ref = f_np(**data)
    print(f'n = {n}')
    for name, func in list(globals().items()):
        if not name.startswith('f_') or not isinstance(func, types.FunctionType):
            continue
        try:
            assert np.all(ref == func(**data))
            print("{:16s}{:16.8f} ms".format(name[2:], timeit(
                'f(**data)', globals={'f':func, 'data':data}, number=10)*100))
        except:
            print("{:16s} apparently crashed".format(name[2:]))

আশ্চর্যের বিষয় হল, বড় ডেটা সেটগুলিতে @ ড্যানিয়েলের খাঁটি পাইথন সমাধানের চেয়ে ন্যাম্পি কিছুটা দ্রুত। নমুনা আউটপুট:

# n = 10
# np                    0.03481400 ms
# py                    0.00669330 ms
# n = 1000
# np                    0.11215360 ms
# py                    0.34836530 ms
# n = 1000000
# np                   82.46765980 ms
# py                  360.51235450 ms

সম্ভবত নেস্টেড বিনগুলি না রেখে অঙ্কের স্ট্রিংটি সমতল করার জন্য উল্লেখযোগ্যভাবে দ্রুত গতিযুক্ত, যদি না এনপপি দক্ষ ইনডেক্স সহ 3 ডি ম্যাট্রিক্স হিসাবে এটি প্রয়োগ না করে। @ ড্যানিয়েলের কোন সংস্করণের বিপরীতে আপনি সময় দিয়েছেন; যেটি প্রতিটি সংখ্যার জন্য স্ট্রিং অনুসন্ধান চালায় বা হিস্টোগ্রামের সাথে?
পিটার

2
@ পিটারকর্ডস আমি এটি সন্দেহ করি। ndarrays, মূল ন্পী টাইপগুলি হ'ল দক্ষ স্টোরেজ, হেরফের এবং সংখ্যার বহুমাত্রিক অ্যারেগুলির সূচীকরণ। কখনও কখনও আপনি চাটুকার দ্বারা কয়েক% মুণ্ডন করতে পারেন, তবে এই ক্ষেত্রে 100 x [0] + 10 x [1] + x [2] হাতে হাতে করা আপনাকে বেশি লাভ করতে পারে না। @ ড্যানিয়েল যেটি বলেছিলেন তা আমি দ্রুত ব্যবহার করেছি, আপনি নিজেই বেনমার্ক কোডটি পরীক্ষা করতে পারেন।
পল প্যানজার 13

আমি আসলেই নম্পপি (বা পাইথনকে সাধারণভাবে জানি না; বেশিরভাগ ক্ষেত্রে আমি সি ৮ এবং এসেম্বলি পারফরম্যান্স টিউনটি x86 এর জন্য করি) তবে আমার মনে হয় আপনার একক থ্রিডি অ্যারে আছে, তাই না? আমি আপনার ইংরেজি পাঠ্যটি (যা স্পষ্টত আমি মনোযোগ দিয়ে পড়িনি) থেকেও ভাবছিলাম যে আপনার কাছে প্রকৃত নেস্টন বস্তু রয়েছে এবং সেগুলি পৃথকভাবে সূচীকরণ করছিলেন। তবে ঘটনাটি নয়, তাই এনভিএম আমার প্রথম মন্তব্য।
পিটার

আমি মনে করি আপনি যে শুদ্ধ পাইথন সংস্করণটি ব্যবহার করেছেন তা হিস্টগ্রাম বাস্তবায়ন যা এমনকি উচ্চতর ভোটিত উত্তর ব্যবহার করেছে, তবে পাইথনে এটি লেখার বিভিন্ন উপায় যদি গতিটিকে অনেক বেশি প্রভাবিত করে।
পিটার কর্ডেস

3

আমি সমস্যাটি নিম্নরূপে সমাধান করব:

def find_numbers(str_num):
    final_dict = {}
    buffer = {}
    for idx in range(len(str_num) - 3):
        num = int(str_num[idx:idx + 3])
        if num not in buffer:
            buffer[num] = 0
        buffer[num] += 1
        if buffer[num] > 1:
            final_dict[num] = buffer[num]
    return final_dict

আপনার উদাহরণের স্ট্রিংয়ের সাথে প্রয়োগ করে, এটি ফলন করে:

>>> find_numbers("123412345123456")
{345: 2, 234: 3, 123: 3}

প্রদত্ত স্ট্রিংটির দৈর্ঘ্য হ'ল এই সমাধানটি ও (এন) এ চলে এবং আমি অনুমান করি যে আপনি সবচেয়ে ভাল পেতে পারেন।


আপনি কেবল একটি ব্যবহার করতে পারে Counter। আপনার একটি দরকার নেই final_dictএবং প্রতিটি পুনরাবৃত্তিতে আপনাকে এটি আপডেট করতে হবে না।
এরিক ডুমিনিল

2

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

কোডটি এরকম কিছু দেখবে:

def calc_repeating_digits(number):

    hash = {}

    for i in range(len(str(number))-2):

        current_three_digits = number[i:i+3]
        if current_three_digits in hash.keys():
            hash[current_three_digits] += 1

        else:
            hash[current_three_digits] = 1

    return hash

আপনি কীগুলিতে ফিল্টার করতে পারেন যার আইটেম মান 1 এর চেয়ে বেশি।


2

অন্য উত্তরে উল্লিখিত হিসাবে, আপনি এই অ্যালগরিদমকে ধ্রুবক সময়ে করতে পারবেন না, কারণ আপনার অবশ্যই কমপক্ষে n সংখ্যাগুলি দেখতে হবে। লিনিয়ার সময় আপনি পেতে পারেন দ্রুত।

তবে অ্যালগরিদম ও (1) স্পেসে করা যেতে পারে । আপনার কেবলমাত্র প্রতিটি 3 ডিজিটের সংখ্যা গণনা করা দরকার তাই আপনার 1000 এন্ট্রিগুলির একটি অ্যারে দরকার। তারপরে আপনি নম্বরটি স্ট্রিম করতে পারবেন।

আমার ধারণাটি হ'ল হয় সাক্ষাত্কারকারীর ভুল সমাধান করা যখন তারা আপনাকে সমাধানটি দিয়েছিল, অথবা আপনি "ধ্রুবক সময়" বলেছেন যখন "ধ্রুবক স্থান" বলে থাকেন he


অন্যরা যেমন উল্লেখ করেছে, হিস্টোগ্রাম পদ্ধতির O(10**d)অতিরিক্ত স্থান, যেখানে dআপনি যে দশমিক সংখ্যার সন্ধান করছেন is
পিটার

1
অভিধানের পদ্ধতির সংখ্যা হ'ল n (মিনিট (10 ^ d, n)) হবে n অঙ্কের জন্য। উদাহরণস্বরূপ যদি আপনার n = 10 ^ 9 সংখ্যা রয়েছে এবং একবারে একাধিকবার দেখা পাওয়া বিরল 15 ডিজিটের সিকোয়েন্সগুলি সন্ধান করতে চান।
gnasher729

1

আমার উত্তর এখানে:

from timeit import timeit
from collections import Counter
import types
import random

def setup_data(n):
    digits = "0123456789"
    return dict(text = ''.join(random.choice(digits) for i in range(n)))


def f_counter(text):
    c = Counter()
    for i in range(len(text)-2):
        ss = text[i:i+3]
        c.update([ss])
    return (i for i in c.items() if i[1] > 1)

def f_dict(text):
    d = {}
    for i in range(len(text)-2):
        ss = text[i:i+3]
        if ss not in d:
            d[ss] = 0
        d[ss] += 1
    return ((i, d[i]) for i in d if d[i] > 1)

def f_array(text):
    a = [[[0 for _ in range(10)] for _ in range(10)] for _ in range(10)]
    for n in range(len(text)-2):
        i, j, k = (int(ss) for ss in text[n:n+3])
        a[i][j][k] += 1
    for i, b in enumerate(a):
        for j, c in enumerate(b):
            for k, d in enumerate(c):
                if d > 1: yield (f'{i}{j}{k}', d)


for n in (1E1, 1E3, 1E6):
    n = int(n)
    data = setup_data(n)
    print(f'n = {n}')
    results = {}
    for name, func in list(globals().items()):
        if not name.startswith('f_') or not isinstance(func, types.FunctionType):
            continue
        print("{:16s}{:16.8f} ms".format(name[2:], timeit(
            'results[name] = f(**data)', globals={'f':func, 'data':data, 'results':results, 'name':name}, number=10)*100))
    for r in results:
        print('{:10}: {}'.format(r, sorted(list(results[r]))[:5]))

অ্যারে দেখার পদ্ধতিটি খুব দ্রুত (@ পল-প্যানজারের নিম্পী পদ্ধতির চেয়েও দ্রুত!)। অবশ্যই এটি প্রতারণা করে যেহেতু এটি সম্পূর্ণ হওয়ার পরে প্রযুক্তিগতভাবে শেষ হয়নি, কারণ এটি কোনও জেনারেটর ফিরিয়ে দিচ্ছে। মানটি ইতিমধ্যে উপস্থিত থাকলে প্রতিটি পুনরাবৃত্তি পরীক্ষা করতে হবে না, যা সম্ভবত অনেক বেশি সাহায্য করবে help

n = 10
counter               0.10595780 ms
dict                  0.01070654 ms
array                 0.00135370 ms
f_counter : []
f_dict    : []
f_array   : []
n = 1000
counter               2.89462101 ms
dict                  0.40434612 ms
array                 0.00073838 ms
f_counter : [('008', 2), ('009', 3), ('010', 2), ('016', 2), ('017', 2)]
f_dict    : [('008', 2), ('009', 3), ('010', 2), ('016', 2), ('017', 2)]
f_array   : [('008', 2), ('009', 3), ('010', 2), ('016', 2), ('017', 2)]
n = 1000000
counter            2849.00500992 ms
dict                438.44007806 ms
array                 0.00135370 ms
f_counter : [('000', 1058), ('001', 943), ('002', 1030), ('003', 982), ('004', 1042)]
f_dict    : [('000', 1058), ('001', 943), ('002', 1030), ('003', 982), ('004', 1042)]
f_array   : [('000', 1058), ('001', 943), ('002', 1030), ('003', 982), ('004', 1042)]

1
তাহলে আপনি ঠিক কি তুলনা করছেন? অব্যবহৃত জেনারেটরের পরিবর্তে আপনার তালিকাগুলি ফিরে আসা উচিত নয়?
এরিক ডুমিনিল 13

Countersযেভাবে ব্যবহার করা হয় না। সঠিকভাবে ব্যবহার করা হলে এগুলি আপনার উদাহরণ সহ দ্রুততম বিকল্পে পরিণত হয়। আপনি ব্যবহার করেন তাহলে timeitএকটি জেনারেটর insted একটি তালিকা সঙ্গে, আপনার পদ্ধতি তুলনায় ধীর হয়ে Counterবা dictএখানে দেখুন ।
এরিক ডুমিনিল

অবশেষে, f_arrayআপনি যদি প্রতিটি চরকে প্রথমে একটি ইনটে: ints = [int(c) for c in text]এবং তারপরে ব্যবহার করেন তবে আপনার দ্রুত হতে পারে i, j, k = ints[n:n+3]
এরিক ডুমিনিল

1

উত্তর হিসাবে চিত্র:

উত্তর হিসাবে চিত্র

স্লাইডিং উইন্ডোর মতো দেখাচ্ছে।


1

এখানে আমার সমাধান:

from collections import defaultdict
string = "103264685134845354863"
d = defaultdict(int)
for elt in range(len(string)-2):
    d[string[elt:elt+3]] += 1
d = {key: d[key] for key in d.keys() if d[key] > 1}

লুপের জন্য কিছুটা সৃজনশীলতার সাথে (এবং সত্য / মিথ্যা / উদাহরণস্বরূপ কিছুই নয়) এর সাথে অতিরিক্ত অনুসন্ধানের তালিকাটি আপনি সর্বশেষ লাইনের হাত থেকে মুক্তি পেতে সক্ষম হবেন, আপনি কেবলমাত্র ডিকটিতে কীগুলি তৈরি করতে চান যা আমরা একবারে এখানে এসেছি । আশা করি এটা সাহায্য করবে :)


দেখুন pho7 এর উত্তর । এবং মন্তব্য। কেন তা বোঝার চেষ্টা করুনএটি ভোটের বোঝা পায় না তা ।
গ্রেইবার্ড

0

সি এর দৃষ্টিকোণ থেকে বলা - আপনি একটি 3-ডি অ্যারের ফলাফল পেতে পারেন [10] [10] [10]; -0 তম অবস্থান থেকে এন -4 র্থ স্থানে যান, যেখানে এন স্ট্রিং অ্যারের আকার হচ্ছে। - প্রতিটি অবস্থানের উপর, বর্তমান এবং পরবর্তী এবং পরবর্তী এর পরীক্ষা করুন। -সেন্ট্রিকে পুনঃসূত্রে হিসাবে বর্তমান [বর্তমান] [পরবর্তী] [পরবর্তী পরবর্তী] ++; এর মান মুদ্রণ করুন

results[1][2][3]
results[2][3][4]
results[3][4][5]
results[4][5][6]
results[5][6][7]
results[6][7][8]
results[7][8][9]

এটি ও (এন) সময়, জড়িত কোনও তুলনা নেই। - আপনি এখানে অ্যারে বিভক্ত করে এবং পার্টিশনের চারপাশের ম্যাচগুলি গণনা করে কিছু সমান্তরাল জিনিস চালাতে পারেন।


-1
inputStr = '123456123138276237284287434628736482376487234682734682736487263482736487236482634'

count = {}
for i in range(len(inputStr) - 2):
    subNum = int(inputStr[i:i+3])
    if subNum not in count:
        count[subNum] = 1
    else:
        count[subNum] += 1

print count

আপনার উত্তরের জন্য ধন্যবাদ তবে এটি একটি অ্যালগরিদমের সাথে অনেকটা অনুরূপ @-6 দিন আগে @ অভিষেক অরোরা দিয়েছিল। এছাড়াও মূল প্রশ্নটি অ্যালগরিদমের জন্য নয় বরং একটি ভিন্ন প্রশ্ন (যা ইতিমধ্যে একাধিকবার উত্তর দেওয়া হয়েছিল)
it.david
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.