मुझे एक साक्षात्कार में यह समस्या दी गई थी। आपने कैसे उत्तर दिया होगा?
एक डेटा संरचना तैयार करें जो O (1) समय में निम्नलिखित संचालन प्रदान करती है:
- डालने
- हटाना
- शामिल
- यादृच्छिक तत्व प्राप्त करें
मुझे एक साक्षात्कार में यह समस्या दी गई थी। आपने कैसे उत्तर दिया होगा?
एक डेटा संरचना तैयार करें जो O (1) समय में निम्नलिखित संचालन प्रदान करती है:
जवाबों:
हैशटेबल एच और एक सरणी से बना डेटा संरचना पर विचार करें। हैशटेबल कुंजी डेटा संरचना में तत्व हैं, और मान सरणी में उनके स्थान हैं।
चूंकि सरणी को आकार में स्वतः वृद्धि की आवश्यकता है, इसलिए यह एक तत्व जोड़ने के लिए O (1) को परिशोधन करने वाला है, लेकिन मुझे लगता है कि यह ठीक है।
O (1) लुकअप का तात्पर्य हैशेड डेटा संरचना से है ।
तुलना से:
hashtable.get((int)(Math.random()*hashtable.size()));
आप इसे पसंद नहीं कर सकते हैं, क्योंकि वे शायद एक चतुर समाधान की तलाश कर रहे हैं, लेकिन कभी-कभी यह आपकी बंदूकों से चिपके रहने के लिए भुगतान करता है ... एक हैश तालिका पहले से ही आवश्यकताओं को संतुष्ट करती है - शायद किसी भी चीज़ की तुलना में समग्र रूप से बेहतर होगा (यद्यपि स्पष्ट रूप से परिशोधन में लगातार समय, और विभिन्न समाधानों के साथ समझौता)।
मुश्किल है कि आवश्यकता "यादृच्छिक तत्व" चयन है: एक हैश तालिका में, आपको ऐसे तत्व के लिए स्कैन या जांच करने की आवश्यकता होगी।
बंद हैशिंग / ओपन एड्रेसिंग के लिए, किसी दिए गए बाल्टी के कब्जे का मौका है size() / capacity()
, लेकिन महत्वपूर्ण रूप से यह आमतौर पर हैश-टेबल कार्यान्वयन द्वारा एक स्थिर गुणन सीमा में रखा जाता है (उदाहरण के लिए तालिका को वर्तमान सामग्री की तुलना में 1.2x गुणा बड़ा रखा जा सकता है) ~ 10x प्रदर्शन / मेमोरी ट्यूनिंग के आधार पर)। इसका मतलब है कि औसतन हम 1.2 से 10 बाल्टियों की खोज कर सकते हैं - कंटेनर के कुल आकार से पूरी तरह से स्वतंत्र; परिशोधन O (1)।
मैं दो सरल दृष्टिकोणों की कल्पना कर सकता हूं (और एक बहुत अधिक काल्पनिक रूप से):
एक यादृच्छिक बाल्टी से रैखिक खोजें
यादृच्छिक बकेट को बार-बार आज़माएं जब तक कि आपको कोई आबादी न मिले
एक महान समाधान नहीं है, लेकिन अभी भी स्मृति और प्रदर्शन की तुलना में एक बेहतर समग्र समझौता हो सकता है जो हर समय एक दूसरे सूचकांक सरणी को बनाए रखने के ओवरहेड्स हो सकता है।
सबसे अच्छा समाधान शायद हैश तालिका + सरणी है, यह वास्तविक तेज़ और निर्धारक है।
लेकिन सबसे कम मूल्यांकित उत्तर (बस हैश टेबल का उपयोग करें!) वास्तव में बहुत अच्छा है!
"संभावित अनंत छोरों" के कारण लोग इसे पसंद नहीं कर सकते हैं, और मैंने देखा है कि बहुत स्मार्ट लोगों की यह प्रतिक्रिया भी होती है, लेकिन यह गलत है! असीम रूप से अप्रत्याशित घटनाओं बस नहीं होता है।
अपने छद्म यादृच्छिक स्रोत के अच्छे व्यवहार को मानते हुए - जो इस विशेष व्यवहार के लिए स्थापित करना मुश्किल नहीं है - और वह हैश टेबल हमेशा कम से कम 20% भरा हो, यह देखना आसान है:
ऐसा कभी नहीं होगा कि getRandom () को 1000 से अधिक बार प्रयास करना पड़े। बस कभी नहीं । वास्तव में, इस तरह की घटना की संभावना 0.8 ^ 1000 है, जो कि 10 ^ -97 है - इसलिए हमें इसे एक बार होने वाले एक अरब में एक मौका होने के लिए इसे 10 ^ 88 बार दोहराना होगा। भले ही यह कार्यक्रम मानव जाति के सभी कंप्यूटरों पर पूर्णकालिक रूप से चल रहा हो, जब तक कि सूर्य की मृत्यु नहीं हो जाती, ऐसा कभी नहीं होगा।
इस प्रश्न के लिए मैं दो डेटा संरचना का उपयोग करूंगा
कदम :-
कोड: -
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
public class JavaApplication1 {
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
ArrayList<Integer> al =new ArrayList<Integer>();
HashMap<Integer,Integer> mp = new HashMap<Integer,Integer>();
while(true){
System.out.println("**menu**");
System.out.println("1.insert");
System.out.println("2.remove");
System.out.println("3.search");
System.out.println("4.rendom");
int ch = sc.nextInt();
switch(ch){
case 1 : System.out.println("Enter the Element ");
int a = sc.nextInt();
if(mp.containsKey(a)){
System.out.println("Element is already present ");
}
else{
al.add(a);
mp.put(a, al.size()-1);
}
break;
case 2 : System.out.println("Enter the Element Which u want to remove");
a = sc.nextInt();
if(mp.containsKey(a)){
int size = al.size();
int index = mp.get(a);
int last = al.get(size-1);
Collections.swap(al, index, size-1);
al.remove(size-1);
mp.put(last, index);
System.out.println("Data Deleted");
}
else{
System.out.println("Data Not found");
}
break;
case 3 : System.out.println("Enter the Element to Search");
a = sc.nextInt();
if(mp.containsKey(a)){
System.out.println(mp.get(a));
}
else{
System.out.println("Data Not Found");
}
break;
case 4 : Random rm = new Random();
int index = rm.nextInt(al.size());
System.out.println(al.get(index));
break;
}
}
}
}
- समय जटिलता ओ (1)। - अंतरिक्ष जटिलता O (N)।
यहाँ उस समस्या का एक C # समाधान है जो मैं एक ही सवाल पूछने पर थोड़ी देर पहले आया था। यह अन्य मानक .NET इंटरफेस के साथ Add, Remove, Contains, और Random लागू करता है। ऐसा नहीं है कि आपको कभी भी एक साक्षात्कार के दौरान इसे इस तरह से लागू करने की आवश्यकता होगी, लेकिन इसे देखने के लिए एक ठोस समाधान करना अच्छा है ...
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
/// <summary>
/// This class represents an unordered bag of items with the
/// the capability to get a random item. All operations are O(1).
/// </summary>
/// <typeparam name="T">The type of the item.</typeparam>
public class Bag<T> : ICollection<T>, IEnumerable<T>, ICollection, IEnumerable
{
private Dictionary<T, int> index;
private List<T> items;
private Random rand;
private object syncRoot;
/// <summary>
/// Initializes a new instance of the <see cref="Bag<T>"/> class.
/// </summary>
public Bag()
: this(0)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Bag<T>"/> class.
/// </summary>
/// <param name="capacity">The capacity.</param>
public Bag(int capacity)
{
this.index = new Dictionary<T, int>(capacity);
this.items = new List<T>(capacity);
}
/// <summary>
/// Initializes a new instance of the <see cref="Bag<T>"/> class.
/// </summary>
/// <param name="collection">The collection.</param>
public Bag(IEnumerable<T> collection)
{
this.items = new List<T>(collection);
this.index = this.items
.Select((value, index) => new { value, index })
.ToDictionary(pair => pair.value, pair => pair.index);
}
/// <summary>
/// Get random item from bag.
/// </summary>
/// <returns>Random item from bag.</returns>
/// <exception cref="System.InvalidOperationException">
/// The bag is empty.
/// </exception>
public T Random()
{
if (this.items.Count == 0)
{
throw new InvalidOperationException();
}
if (this.rand == null)
{
this.rand = new Random();
}
int randomIndex = this.rand.Next(0, this.items.Count);
return this.items[randomIndex];
}
/// <summary>
/// Adds the specified item.
/// </summary>
/// <param name="item">The item.</param>
public void Add(T item)
{
this.index.Add(item, this.items.Count);
this.items.Add(item);
}
/// <summary>
/// Removes the specified item.
/// </summary>
/// <param name="item">The item.</param>
/// <returns></returns>
public bool Remove(T item)
{
// Replace index of value to remove with last item in values list
int keyIndex = this.index[item];
T lastItem = this.items[this.items.Count - 1];
this.items[keyIndex] = lastItem;
// Update index in dictionary for last item that was just moved
this.index[lastItem] = keyIndex;
// Remove old value
this.index.Remove(item);
this.items.RemoveAt(this.items.Count - 1);
return true;
}
/// <inheritdoc />
public bool Contains(T item)
{
return this.index.ContainsKey(item);
}
/// <inheritdoc />
public void Clear()
{
this.index.Clear();
this.items.Clear();
}
/// <inheritdoc />
public int Count
{
get { return this.items.Count; }
}
/// <inheritdoc />
public void CopyTo(T[] array, int arrayIndex)
{
this.items.CopyTo(array, arrayIndex);
}
/// <inheritdoc />
public bool IsReadOnly
{
get { return false; }
}
/// <inheritdoc />
public IEnumerator<T> GetEnumerator()
{
foreach (var value in this.items)
{
yield return value;
}
}
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
/// <inheritdoc />
public void CopyTo(Array array, int index)
{
this.CopyTo(array as T[], index);
}
/// <inheritdoc />
public bool IsSynchronized
{
get { return false; }
}
/// <inheritdoc />
public object SyncRoot
{
get
{
if (this.syncRoot == null)
{
Interlocked.CompareExchange<object>(
ref this.syncRoot,
new object(),
null);
}
return this.syncRoot;
}
}
}
ArgumentException
संदेश के साथ जोड़ा जाता है "एक ही कुंजी के साथ एक आइटम पहले ही जोड़ा जा चुका है।" फेंक दिया जाएगा (अंतर्निहित इंडेक्स डिक्शनरी से)।
हम) (1) समय में संचालन का समर्थन करने के लिए हैशिंग का उपयोग कर सकते हैं।
डालें (x) 1) जांचें कि क्या x पहले से ही हैश मैप लुकअप करके मौजूद है। 2) यदि मौजूद नहीं है, तो इसे सरणी के अंत में डालें। 3) हैश तालिका में भी जोड़ें, x को इंडेक्स के रूप में कुंजी और अंतिम सरणी इंडेक्स के रूप में जोड़ा जाता है।
निकालें (x) 1) जांचें कि क्या x हैश मैप लुकअप करके मौजूद है। 2) यदि मौजूद है, तो उसका इंडेक्स ढूंढें और उसे हैश मैप से हटा दें। 3) इस तत्व के साथ अंतिम तत्व को सरणी में स्वैप करें और अंतिम तत्व को हटा दें। स्वैपिंग किया जाता है क्योंकि अंतिम तत्व को ओ (1) समय में हटाया जा सकता है। 4) हैश मैप में अंतिम तत्व का अपडेट इंडेक्स।
getRandom () 1) 0 से अंतिम इंडेक्स तक एक यादृच्छिक संख्या उत्पन्न करता है। 2) बेतरतीब ढंग से उत्पन्न सूचकांक पर सरणी तत्व लौटें।
खोज (एक्स) हैश मानचित्र में एक्स के लिए एक खोज करते हैं।
हालांकि यह पुराना है, लेकिन चूंकि C ++ में इसका कोई जवाब नहीं है, इसलिए यहां मेरे दो सेंट हैं।
#include <vector>
#include <unordered_map>
#include <stdlib.h>
template <typename T> class bucket{
int size;
std::vector<T> v;
std::unordered_map<T, int> m;
public:
bucket(){
size = 0;
std::vector<T>* v = new std::vector<T>();
std::unordered_map<T, int>* m = new std::unordered_map<T, int>();
}
void insert(const T& item){
//prevent insertion of duplicates
if(m.find(item) != m.end()){
exit(-1);
}
v.push_back(item);
m.emplace(item, size);
size++;
}
void remove(const T& item){
//exits if the item is not present in the list
if(m[item] == -1){
exit(-1);
}else if(m.find(item) == m.end()){
exit(-1);
}
int idx = m[item];
m[v.back()] = idx;
T itm = v[idx];
v.insert(v.begin()+idx, v.back());
v.erase(v.begin()+idx+1);
v.insert(v.begin()+size, itm);
v.erase(v.begin()+size);
m[item] = -1;
v.pop_back();
size--;
}
T& getRandom(){
int idx = rand()%size;
return v[idx];
}
bool lookup(const T& item){
if(m.find(item) == m.end()) return false;
return true;
}
//method to check that remove has worked
void print(){
for(auto it = v.begin(); it != v.end(); it++){
std::cout<<*it<<" ";
}
}
};
समाधान का परीक्षण करने के लिए यहां ग्राहक कोड का एक टुकड़ा है।
int main() {
bucket<char>* b = new bucket<char>();
b->insert('d');
b->insert('k');
b->insert('l');
b->insert('h');
b->insert('j');
b->insert('z');
b->insert('p');
std::cout<<b->random()<<std::endl;
b->print();
std::cout<<std::endl;
b->remove('h');
b->print();
return 0;
}
C # 3.0 + .NET फ्रेमवर्क 4 में, एक जेनेरिक Dictionary<TKey,TValue>
हैशटेबल से भी बेहतर है क्योंकि आप System.Linq
एक्सटेंशन विधि ElementAt()
को अंतर्निहित डायनेमिक सरणी में इंडेक्स करने के लिए उपयोग कर सकते हैं जहां KeyValuePair<TKey,TValue>
तत्व संग्रहीत हैं:
using System.Linq;
Random _generator = new Random((int)DateTime.Now.Ticks);
Dictionary<string,object> _elements = new Dictionary<string,object>();
....
Public object GetRandom()
{
return _elements.ElementAt(_generator.Next(_elements.Count)).Value;
}
हालाँकि, जहां तक मुझे पता है, एक हैशटेबल (या इसके शब्दकोश संतान) इस समस्या का वास्तविक समाधान नहीं है क्योंकि पुट () केवल O (1) को परिशोधित किया जा सकता है, सत्य O (1) नहीं, क्योंकि यह O (N) है ) गतिशील आकार सीमा पर।
क्या इस समस्या का वास्तविक समाधान है? मैं बस यही सोच सकता हूं कि यदि आप एक डिक्शनरी / हैशटेबल प्रारंभिक क्षमता को एक परिमाण के क्रम से आगे बढ़ाते हैं जो आप कभी भी अपेक्षित होने की उम्मीद करते हैं, तो आपको ओ (1) संचालन मिलता है क्योंकि आपको कभी भी आकार बदलने की आवश्यकता नहीं होती है।
मैं एनॉन से सहमत हूं। अंतिम आवश्यकता को छोड़कर जहां समान निष्पक्षता के साथ एक यादृच्छिक तत्व प्राप्त करना आवश्यक है अन्य सभी आवश्यकताओं को केवल एक हैश आधारित डीएस का उपयोग करके संबोधित किया जा सकता है। मैं इसके लिए HashSet को Java में चुनूंगा। किसी तत्व के हैश कोड का मोड्यूल मुझे O (1) समय में अंतर्निहित सरणी का सूचकांक नहीं देगा। मैं इसे जोड़ने, हटाने और संचालन के लिए उपयोग कर सकता हूं।
खिचड़ी भाषा हम जावा के हैशसेट का उपयोग करते हैं? यह डिफ़ॉल्ट रूप से ओ (1) में सभी सम्मिलित, डेल, खोज प्रदान करता है। GetRandom के लिए हम सेट के iterator का उपयोग कर सकते हैं जो वैसे भी यादृच्छिक व्यवहार देता है। हम बाकी तत्वों के बारे में चिंता किए बिना सेट से पहले तत्व को पुनरावृत्त कर सकते हैं
public void getRandom(){
Iterator<integer> sitr = s.iterator();
Integer x = sitr.next();
return x;
}
/* Java program to design a data structure that support folloiwng operations
in Theta(n) time
a) Insert
b) Delete
c) Search
d) getRandom */
import java.util.*;
// class to represent the required data structure
class MyDS
{
ArrayList<Integer> arr; // A resizable array
// A hash where keys are array elements and vlaues are
// indexes in arr[]
HashMap<Integer, Integer> hash;
// Constructor (creates arr[] and hash)
public MyDS()
{
arr = new ArrayList<Integer>();
hash = new HashMap<Integer, Integer>();
}
// A Theta(1) function to add an element to MyDS
// data structure
void add(int x)
{
// If ekement is already present, then noting to do
if (hash.get(x) != null)
return;
// Else put element at the end of arr[]
int s = arr.size();
arr.add(x);
// And put in hash also
hash.put(x, s);
}
// A Theta(1) function to remove an element from MyDS
// data structure
void remove(int x)
{
// Check if element is present
Integer index = hash.get(x);
if (index == null)
return;
// If present, then remove element from hash
hash.remove(x);
// Swap element with last element so that remove from
// arr[] can be done in O(1) time
int size = arr.size();
Integer last = arr.get(size-1);
Collections.swap(arr, index, size-1);
// Remove last element (This is O(1))
arr.remove(size-1);
// Update hash table for new index of last element
hash.put(last, index);
}
// Returns a random element from MyDS
int getRandom()
{
// Find a random index from 0 to size - 1
Random rand = new Random(); // Choose a different seed
int index = rand.nextInt(arr.size());
// Return element at randomly picked index
return arr.get(index);
}
// Returns index of element if element is present, otherwise null
Integer search(int x)
{
return hash.get(x);
}
}
// Driver class
class Main
{
public static void main (String[] args)
{
MyDS ds = new MyDS();
ds.add(10);
ds.add(20);
ds.add(30);
ds.add(40);
System.out.println(ds.search(30));
ds.remove(20);
ds.add(50);
System.out.println(ds.search(50));
System.out.println(ds.getRandom());`enter code here`
}
}
यादृच्छिक तत्व को खोजने के लिए हम एपोक% सरणियों का उपयोग क्यों नहीं करते हैं। सरणी का आकार ढूँढना O (n) है, लेकिन परिशोधित जटिलता O (1) होगी।
मुझे लगता है कि हम हैश टेबल के साथ दोगुनी लिंक सूची का उपयोग कर सकते हैं। कुंजी तत्व होगा और इसका संबद्ध मूल्य दोगुनी लिंकलिस्ट में नोड होगा।