-
Notifications
You must be signed in to change notification settings - Fork 4
/
AlgosGeneralConceptIQs.txt
executable file
·1676 lines (1287 loc) · 84.2 KB
/
AlgosGeneralConceptIQs.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1. Merge Sort vs Quick Sort
1b. Bubble Sort vs QuickSort
2. Bubble Sort vs Selection Sort vs Insertion Sort
2b. When to use what sorting algorithm
2c. Stable Sort vs Unstable Sort
2d. What is Intro Sort
3. Median of Medians:
4. Bit twiddling Stanford material
4b. Count bits set in a number
4c. Set, Unset, Clear, Toggle a Bit
4d. Absolute Value of a number
4e. Reverse Bits in a number
4f. Find leftmost set bit in a number
4g. Find rightmost set bit in a number
5. String Search:
6. Given 2 sorted arrays of integers, find the nth largest number in sublinear time
7. k'th smallest in Union of Two arrays:
8. K’th Smallest/Largest Element in Unsorted Array | Set 3 (Worst Case Linear Time)
9. GCD of two numbers:
10. STOCK PROBLEMS:
11. Sorted Rotated Array:
12. Find all subsets of a set
13. Multiplication of two numers (without using *)
14. Spiral Level Order traversal of a tree
15. Space Complexity for Tree Traversal.
16. Memoization vs Tabulation in Dynamic Programming
17. How to efficiently check whether it's height balanced for a massively skewed binary search tree
18. How to determine if binary tree is balanced
19. Explain Morris inorder tree traversal without using stacks or recursion
20. Count subsequences divisible by K
21. Merge Overlapping intervals
22. Finding all subsets of a Vector of Vector
23. Converting Recursive Algorithm to Iterative
24. Balancing Binary Search Trees
25. Balancing a Heap
26. Why is Heapify O(n)
26b. SiftUp vs SiftDown
27. n way merge
28. B Tree vs B+ Tree
29. Heap vs Binary Search Tree
30. Smallest range that includes at least one number from each of the k lists
31. Select a random number from stream, with O(1) space
32. Design a data structure that supports insert, delete, search and getRandom in constant time
33. Check if a given array contains duplicate elements within k distance from each other
34. Reservoir Sampling
35. Search a Word in a 2D Grid of characters
36. Sort countries based on population
37. Average of a number accounting for integer overflow
38. Swap Endianess / Converting Little Endian to Big Endian
39. How many traversals need to be known to construct a BST
40. Trie vs Ternary Search Tree
41. Find number of possible perfect squares between two numbers
42. Check if an Intger is a perfect square
43. How will you implement your own malloc
44. How will you implement your own memcpy
45. If you are given two traversal sequences, can you construct the binary tree
46. Unique (non-repeating) random numbers in O(1)?
47. Persistent Data Structures (Fully Persistent and Partially Persistent)
48. Bellman Ford - Shortest Path
49. Coin Arbitrage Algorithm
50. Graph Algorigthms
51. Examples of Data Structures in real life
52. The Most Efficient Way To Find Top K Frequent Words In A Big Word Sequence
53. How to count number of requests in last second, minute and hour
--------------------------------------------------------------------------------------------
1.
Merge Sort vs Quick Sort
http://stackoverflow.com/questions/5222730/why-is-merge-sort-preferred-over-quick-sort-for-sorting-linked-lists?rq=1
http://www.geeksforgeeks.org/why-quick-sort-preferred-for-arrays-and-merge-sort-for-linked-lists/
http://stackoverflow.com/questions/2467751/quicksort-vs-heapsort
- "Merge sort is very efficient for immutable datastructures like linked lists"
- "Quick sort is typically faster than merge sort when the data is stored in memory.
MERGE SORT PROS
- ACCESSES DATA SEQUENTIALLY
- Quicksort is also more complicated than mergesort, especially if you want to write a really solid implementation
- Can easily insert elements in the middle
- So MERGE doesnot need any extra overhead
- However, when the data set is huge and is stored on external devices such as a hard drive, merge sort is the clear winner in terms of speed.
- It minimizes the expensive reads of the external drive" "when operating on linked lists
- Merge sort only requires a small constant amount of auxiliary storage"
QUICK SORT PROS
- ACCESSES DATA RANDOMLY
- Quicksort is significantly faster in practice than other T(nlogn) algorithms,
- Because its inner loop can be efficiently implemented on most architectures,
- In most real-world data, it is possible to make design choices which minimize the probability of requiring quadratic time
- Quick sort is space constant where Merge sort depends on the structure you're sorting
- Best when able to index into an array or similar structure.
You would want to access elements at random positions
When that's possible, it's hard to beat Quicksort.
- Quicksort is fast when the data fits into memory and can be addressed directly
- Practically, Quicksort runs fast, much faster than Heap and Merge algorithms.
- The secret of Quicksort is: It almost doesn't do unnecessary element swaps.
Swap is time consuming.
HEAPSORT MERGESORT AND QUICKSORT
- With HEAPSORT, even if all of your data is already ordered, you are going to swap 100% of elements to order the array.
- With MERGESORT, it's even worse. You are going to write 100% of elements in another array and write it back in the original one, even if data is already ordered.
- With QUICKSORT you don't swap what is already ordered. If your data is completely ordered, you swap almost nothing
IMP:
- Array of equal elements.
while (a[i] < pivot) {i++;}
while (pivot < a[j] ) {j--;}
if (i < j) swap (a[i], a[j]);
If we have an array of equal elements, the second code will never increment i or decrement j
http://faculty.simpson.edu/lydia.sinapova/www/cmsc250/LN250_Tremblay/L06-QuickSort.htm
VERY IMP:
CHECK IF "i <= j"
After doing a SWAP, decrement j and increment i.
This is get over duplicate elements.
http://www.algolist.net/Algorithms/Sorting/Quicksort
3 way partition:
Nice explanation of the algorithm:
http://algs4.cs.princeton.edu/lectures/23DemoPartitioning.pdf
Dutch National Flag Problem:
http://stackoverflow.com/questions/11214089/understanding-dutch-national-flag-program
Merge Sort:
- Faster when reading from Disk and not everything can be in memory
- Mergesort is faster when data won't fit into memory or when it's expensive to get to an item.
1b. Bubble Sort vs QuickSort
If the array is almost sorted, Bubble sort is faster than Quick Sort
2.
Bubble Sort vs Selection Sort vs Insertion Sort
http://www.sorting-algorithms.com/selection-sort
Bubble Sort:
- Check pair of elements and swap them so that the largest gets bubbled to the end.
PROS:
If array is almost sorted OR once we have the array sorted, we can STOP there.
Bubble sort has many of the same properties as insertion sort, but has slightly higher overhead.
In the case of nearly sorted data, bubble sort takes O(n) time, but requires at least 2 passes through the data (whereas insertion sort requires something more like 1 pass).
Insertion Sort:
- What we have at any given time is sorted.
PROS:
Online Sorting
Can do binary search for inserting into a position
Although it is one of the elementary sorting algorithms with O(n2) worst-case time,
insertion sort is the algorithm of choice either when the data is nearly sorted (because it is adaptive) or when the problem size is small (because it has low overhead).
For these reasons, and because it is also stable, insertion sort is often used as the recursive base case
(when the problem size is small) for higher overhead divide-and-conquer sorting algorithms, such as merge sort or quick sort.
BUBBLE SORT vs INSERTION SORT
In insertion sort elements are bubbled into the sorted section, while in bubble sort the maximums are bubbled out of the unsorted section.
Bubble sort always takes one more pass over array to determine if it's sorted.
On the other hand, insertion sort not need this -- once last element inserted, algorithm guarantees that array is sorted.
Bubble sort does n comparisons on every pass.
Insertion sort does less than n comparisons -- once algorith finds position where to insert current element it stops making comparisons and takes next element.
Selection Sort:
Select Minimum element each time and put it at the front.
PROS:
- Never have to do MORE THAN "n" swaps.
From the comparions presented here, one might conclude that selection sort should never be used.
It does not adapt to the data in any way (notice that the four animations above run in lock step), so its runtime is always quadratic.
However, selection sort has the property of minimizing the number of swaps.
In applications where the cost of swapping items is high, selection sort very well may be the algorithm of choice.
https://www.careercup.com/question?id=4620408242307072
Bubble/insertion/merge sorts are stable.
Selection/quick/heap sorts are not stable.
Selection Sort : Best Worst Average Case running time all O(n^2). However the number of swaps required is always n-1. Hence it is useful when the amount of satellite data(auxiliary data aside from the key) is large and for some reason pointer based swapping is not feasible.
Insertion Sort : Best case running time is O(n). Hence useful for adding new data to a presorted list. Also this is fast when the number of elements is small/ you need an online algorithm.
Bubble Sort:Where we know the data is very nearly sorted. Say only two elements are out of place. Then in one pass, BS will finish it and in the second pass, it will see everything is sorted and then exit. Only takes 2 passes of the array.
Merge Sort : For external sorting algorithms, it is the choice of sort.
Quicksort : Remember that quicksort is dependent on choice of pivot. So when we have absolutely random data values, and we will need to sort them, we have to use quick sort. Even for very unbalanced split QS produces good results.
Heap Sort: It is an inplace O(n logn) algorithm hence we can use it when we cannot afford the extra space required for merge sort. Also has a O(n logn) worst case time as compared to O(n^2) of quicksort
2b.
When to use what sorting algorithm
http://stackoverflow.com/questions/1933759/when-is-each-sorting-algorithm-used
Quick sort:
- When you don't need a STABLE SORT and average case performance matters more than worst case performance.
- A good implementation uses O(log N) auxiliary storage in the form of stack space for recursion
Merge sort:
- When you need a STABLE, O(N log N) sort, this is about your only option.
- The only downsides to it are that it uses O(N) auxiliary space and has a slightly larger constant than a quick sort.
- There are some in-place merge sorts, but AFAIK they are all either not stable or worse than O(N log N).
- Even the O(N log N) in place sorts have so much larger a constant than the plain old merge sort that they're more theoretical curiosities than useful algorithms.
Heap sort:
- When you DON'T NEED A STABLE SORT and you care more about worst case performance than average case performance.
- It's guaranteed to be O(N log N), and uses O(1) auxiliary space, meaning that you won't unexpectedly run out of heap or stack space on very large inputs.
Introsort:
- This is a quick sort that switches to a heap sort after a certain recursion depth to get around quick sort's O(N^2) worst case.
- It's almost always better than a plain old quick sort, since you get the average case of a quick sort, with guaranteed O(N log N) performance.
- Probably the only reason to use a HEAP SORT instead of this is in SEVERELY MEMORY CONSTRAINED systems where O(log N) stack space is practically significant.
Insertion sort:
- When N is guaranteed to be small, including as the base case of a quick sort or merge sort.
- While this is O(N^2), it has a very small constant and is a stable sort.
Bubble sort, selection sort:
- When you're doing something quick and dirty and for some reason you can't just use the standard library's sorting algorithm.
- The only advantage these have over insertion sort is being slightly easier to implement.
NON-COMPARISON SORTS:
Under some fairly limited conditions it's possible to break the O(N log N) barrier and sort in O(N). Here are some cases where that's worth a try:
Counting sort:
When you are sorting integers with a limited range.
Radix sort:
When log(N) is significantly larger than K, where K is the number of radix digits.
Bucket sort:
When you can guarantee that your input is approximately uniformly distributed
2c.
Stable Sort vs Unstable Sort
http://stackoverflow.com/questions/8311090/why-not-use-heap-sort-always
A stable sort maintains the relative order of items that have the same key.
For example, imagine your data set contains records with an employee id and a name.
The initial order is:
1, Jim
2, George
3, Jim
4, Sally
5, George
You want to sort by name. A stable sort will arrange the items in this order:
2, George
5, George
1, Jim
3, Jim
4, Sally
Note that the duplicate records for "George" are in the same relative order as they were in the initial list.
Same with the two "Jim" records.
An unstable sort might arrange the items like this:
5, George
2, George
1, Jim
3, Jim
4, Sally
Heapsort is not stable because operations on the heap can change the relative order of equal items.
Not all Quicksort implementations are stable.
It depends on how you implement the partitioning.
2d.
What is Intro Sort
Introsort or introspective sort is a hybrid sorting algorithm that provides both fast average performance and (asymptotically) optimal worst-case performance.
It begins with quicksort and switches to heapsort when the recursion depth exceeds a level based on (the logarithm of) the number of elements being sorted
3.
Median of Medians:
http://stackoverflow.com/questions/12545795/explanation-of-the-median-of-medians-algorithm
http://stackoverflow.com/questions/9489061/understanding-median-of-medians-algorithm?rq=1
Think of the following set of numbers:
5 2 6 3 1
The median of these numbers is 3. Now if you have a number n, if n > 3, then it is bigger than at least half of the numbers above. If n < 3, then it is smaller than at least half of the numbers above.
So that is the idea. That is, for each set of 5 numbers, you get their median. Now you have n / 5 numbers. This is obvious.
Now if you get the median of those numbers (call it m), it is bigger than half of them and smaller than the other half (by definition of median!). In other words, m is bigger than n / 10 numbers (which themselves were medians of small 5 element groups) and bigger than another n / 10 numbers (which again were medians of small 5 element groups).
In the example above, we saw that if the median is k and you have m > k, then m is also bigger than 2 other numbers (that were themselves smaller than k). This means that for each of those smaller 5 element groups where m was bigger than its medium, m is bigger also than two other numbers. This makes it at least 3 numbers (2 numbers + the median itself) in each of those n / 10 small 5 element groups, that are smaller than m. Hence, m is at least bigger than 3n/10 numbers.
Similar logic for the number of elements m is bigger than.
http://stackoverflow.com/questions/9489061/understanding-median-of-medians-algorithm
// L is the array on which median of medians needs to be found.
// k is the expected median position. E.g. first select call might look like:
// select (array, N/2), where 'array' is an array of numbers of length N
select(L,k)
{
if (L has 5 or fewer elements) {
sort L
return the element in the kth position
}
partition L into subsets S[i] of five elements each
(there will be n/5 subsets total).
for (i = 1 to n/5) do
x[i] = select(S[i],3)
M = select({x[i]}, n/10)
// The code to follow ensures that even if M turns out to be the
// smallest/largest value in the array, we'll get the kth smallest
// element in the array
// Partition array into three groups based on their value as
// compared to median M
partition L into L1<M, L2=M, L3>M
// Compare the expected median position k with length of first array L1
// Run recursive select over the array L1 if k is less than length
// of array L1
if (k <= length(L1))
return select(L1,k)
// Check if k falls in L3 array. Recurse accordingly
else if (k > length(L1)+length(L2))
return select(L3,k-length(L1)-length(L2))
// Simply return M since k falls in L2
else return M
}
4.
Bit twiddling Stanford material
http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable
4b.
Count bits set in a number
http://stackoverflow.com/questions/22081738/how-variable-precision-swar-algorithm-works
http://stackoverflow.com/questions/109023/how-to-count-the-number-of-set-bits-in-a-32-bit-integer
int SWAR(unsigned int i)
{
// Count the number of bits set in TWO bits at a time. Like Bits 1,2; 3,4; 5,6 etc
i = i - ((i >> 1) & 0x55555555);
// Count the number of bits set in FOUR bits at a time. Like Bits 1,2,3,4; 5,6,7,8 etc
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
// Count the number of bits set in EIGHT bits
// (i + (i >> 4)) & 0x0f0f0f0f
// since 0x01010101 = (1 << 24) + (1 << 16) + (1 << 8) + 1, we have:
// k * 0x01010101 = (k << 24) + (k << 16) + (k << 8) + k
// Add all the number of 1s in EIGHT BITS into the highest ordered byte.
// We want the last 8 bytes to represent the number of 1s. So right shift >> 24.
return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}
unsigned int countSetBits(int n)
{
unsigned int count = 0;
while (n)
{
n &= (n-1) ;
count++;
}
return count;
}
4c.
Set, Unset, Clear, Toggle a Bit
http://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit-in-c-c?rq=1
Setting a bit
number |= 1 << x;
Clearing a bit
number &= ~(1 << x);
Toggling a bit
number ^= 1 << x;
Checking a bit
bit = (number >> x) & 1;
4d.
Absolute Value of a number
http://stackoverflow.com/questions/12041632/how-to-compute-the-integer-absolute-value
Let's assume a twos-complement number (as it's the usual case and you don't say otherwise) and let's assume 32-bit:
First, we perform an arithmetic right-shift by 31 bits.
This shifts in all 1s for a negative number or all 0s for a positive one (but note that the actual >>-operator's behaviour in C or C++ is implementation defined for negative numbers, but will usually also perform an arithmetic shift, but let's just assume pseudocode or actual hardware instructions, since it sounds like homework anyway):
mask = x >> 31;
So what we get is 111...111 (-1) for negative numbers and 000...000 (0) for positives
Now we XOR this with x, getting the behaviour of a NOT for mask=111...111 (negative) and a no-op for mask=000...000 (positive):
x = x XOR mask;
And finally subtract our mask, which means +1 for negatives and +0/no-op for positives:
x = x - mask;
So for positives we perform an XOR with 0 and a subtraction of 0 and thus get the same number.
And for negatives, we got (NOT x) + 1, which is exactly -x when using twos-complement representation
4e.
Reverse Bits in a number
http://stackoverflow.com/questions/845772/how-to-check-if-the-binary-representation-of-an-integer-is-a-palindrome
http://www.geeksforgeeks.org/write-an-efficient-c-program-to-reverse-bits-of-a-number/
{
uint32_t revNum = 0;
uint32_t numBits = (int)log2(num) + 1;
for (; num; num >>= 1)
{
revNum = (revNum << 1) | (num & 1);
}
revNum = revNum << ((sizeof(num) * 8) - numBits)
}
unsigned int reverseBits(unsigned int num)
{
unsigned int NO_OF_BITS = sizeof(num) * 8;
unsigned int reverse_num = 0;
int i;
for (i = 0; i < NO_OF_BITS; i++)
{
if((num & (1 << i)))
reverse_num |= 1 << ((NO_OF_BITS - 1) - i);
}
return reverse_num;
}
// Using bit shift
unsigned int v; // 32-bit word to reverse bit order
// swap odd and even bits
v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1);
// swap consecutive pairs
v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2);
// swap nibbles ...
v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4);
// swap bytes
v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8);
// swap 2-byte long pairs
v = ( v >> 16 ) | ( v << 16);
4f.
Find leftmost set bit in a number
http://stackoverflow.com/questions/53161/find-the-highest-order-bit-in-c
1 -> 1
2 -> 2
3 -> 2
4 -> 4
5 -> 4
6 -> 4
7 -> 4
8 -> 8
9 -> 8
...
63 -> 32
1 << ( int) log2( x)
int hibit(unsigned int n)
{
n |= (n >> 1);
n |= (n >> 2);
n |= (n >> 4);
n |= (n >> 8);
n |= (n >> 16);
return n - (n >> 1);
}
int hob (int num)
{
if (!num)
return 0;
int ret = 1;
while (num >>= 1)
ret <<= 1;
return ret;
}
hob(1234) returns 1024
hob(1024) returns 1024
hob(1023) returns 512
4g.
Find rightmost set bit in a number
http://algorithmsandme.in/2013/10/fun-with-bits-find-rightmost-bit-set-in-given-number/
http://www.geeksforgeeks.org/position-of-rightmost-set-bit/
unsigned int getFirstSetBitPos(int n)
{
return log2(n&-n)+1;
}
x & ~(x-1)
To Clear rightmost set bit just do
x & (x-1)
4h.
Compute the minimum (min) or maximum (max) of two integers without branching
int x; // we want to find the minimum of x and y
int y;
int r; // the result goes here
r = y ^ ((x ^ y) & -(x < y)); // min(x, y)
r = x ^ ((x ^ y) & -(x < y)); // max(x, y)
It works because if x < y, then -(x < y) will be all ones, so r = y ^ (x ^ y) & ~0 = y ^ x ^ y = x.
Otherwise, if x >= y, then -(x < y) will be all zeros, so r = y ^ ((x ^ y) & 0) = y.
4i.
Compute the sign of an integer
int v; // we want to find the sign of v
int sign; // the result goes here
// CHAR_BIT is the number of bits per byte (normally 8).
sign = -(v < 0); // if v < 0 then -1, else 0.
// or, for one less instruction (but not portable):
sign = v >> (sizeof(int) * CHAR_BIT - 1);
5.
String Search:
Bayer More:
http://www.geeksforgeeks.org/pattern-searching-set-7-boyer-moore-algorithm-bad-character-heuristic/
6.
Given 2 sorted arrays of integers, find the nth largest number in sublinear time
http://stackoverflow.com/questions/4686823/given-2-sorted-arrays-of-integers-find-the-nth-largest-number-in-sublinear-time
I think this is two concurrent binary searches on the subarrays A[0..n-1] and B[0..n-1], which is O(log n).
Given sorted arrays, you know that the nth largest will appear somewhere before or at A[n-1] if it is in array A, or B[n-1] if it is in array B
Consider item at index a in A and item at index b in B.
Perform binary search as follows (pretty rough pseudocode, not taking in account 'one-off' problems):
If a + b > n, then reduce the search set
if A[a] > B[b] then b = b / 2, else a = a / 2
If a + b < n, then increase the search set
if A[a] > B[b] then b = 3/2 * b, else a = 3/2 * a (halfway between a and previous a)
If a + b = n then the nth largest is max(A[a], B[b])
I believe worst case O(ln n), but in any case definitely sublinear.
7.
k'th smallest in Union of Two arrays:
http://articles.leetcode.com/2011/01/find-k-th-smallest-element-in-union-of.html
8.
K’th Smallest/Largest Element in Unsorted Array | Set 3 (Worst Case Linear Time)
http://www.geeksforgeeks.org/kth-smallestlargest-element-unsorted-array-set-3-worst-case-linear-time/
http://www.programcreek.com/2014/05/leetcode-kth-largest-element-in-an-array-java/
9.
GCD of two numbers:
GCD(a,b) = GCD(b,a-b)
GCD(a,b) = GCD(b,a%b)
NICE IMP Proof:
https://www.khanacademy.org/computing/computer-science/cryptography/modarithmetic/a/the-euclidean-algorithm
https://www.geeksforgeeks.org/c-program-find-gcd-hcf-two-numbers/
// Recursive function to return gcd of a and b
static int gcd(int a, int b)
{
if (b == 0)
return a;
return gcd(b, a % b);
}
10.
STOCK PROBLEMS:
http://stackoverflow.com/questions/9514191/maximizing-profit-for-given-stock-quotes
Traverse Backwards
http://stackoverflow.com/questions/1663545/find-buy-sell-prices-in-array-of-stock-values-to-maximize-positive-difference
http://stackoverflow.com/questions/7086464/maximum-single-sell-profit
11.
Sorted Rotated Array:
In a rotated sorted array, only one of A and B can be guaranteed to be sorted. If the element lies within a part which is sorted, then the solution is simple:
just perform the search as if you were doing a normal binary search. If, however, you must search an unsorted part,
then just recursively call your search function on the non-sorted part.
This ends up giving on a time complexity of O(lg n).
12.
Find all subsets of a set
http://stackoverflow.com/questions/728972/finding-all-the-subsets-of-a-set
http://www.geeksforgeeks.org/power-set/
http://stackoverflow.com/questions/15726641/find-all-possible-substring-in-fastest-way
for (int i = 0; i < A.length(); i++) {
for (int j = i+1; j <= A.length(); j++) {
System.out.println(A.substring(i,j));
}
}
13.
Multiplication of two numers (without using *)
http://stackoverflow.com/questions/28888068/time-complexity-of-russian-peasant-multiplication-algorithm
Using LOG:
10^(log10(A) + log10(B))
i.e. pow(10, log10(A) + log10(B)
Use bit shifting AKA
https://en.wikipedia.org/wiki/Multiplication_algorithm#Peasant_or_binary_multiplication
Decimal: Binary:
11 3 1011 11
5 6 101 110
2 12 10 1100
1 24 1 11000
-- ------
33 100001
The method works because multiplication is distributive, so:
3 * 11 & = 3 * (1 * 2^0 + 1 * 2^1 + 0 * 2^2 + 1 * 2^3)
= 3 * (1 + 2 + 8)
= 3 + 6 + 24
= 33
IMP:
1. Time complexity depends on the NUMBER that we are using for doing the shift
log (a) or log(b) based on which we select as A
2. In the above example say 11 = A and 3 = B
- Select A such that it has lesser number of bits.
- We are repeating the multiplication till A REACHES 1.
- So select A as the number that has least number of bits set.
14.
Spiral Level Order traversal of a tree
http://www.geeksforgeeks.org/level-order-traversal-in-spiral-form/
http://stackoverflow.com/questions/17485773/print-level-order-traversal-of-binary-tree-in-zigzag-manner
You have to use two stacks
1. first stack for printing from left to right
2. second stack for printing from right to left.
Start from the root node.
Store it's children in one stack.
In every iteration, you have nodes of one level in one of the stacks.
Print the nodes, and push nodes of next level in other stack.
Repeat until your reach the final level.
Time Complexity O(n) and space complexity O(h).
15.
Space Complexity for Tree Traversal.
O(h) where h is the height of the tree.
At any time in the stack we will have ones in that depth level
So space complexity is height of tree.
BFS:
Time complexity is O(|V|) where |V| is the number of nodes,you need to traverse all nodes.
Space complecity is O(|V|) as well - since at worst case you need to hold all vertices in the queue.
DFS:
Time complexity is again O(|V|), you need to traverse all nodes.
Space complexity - depends on the implementation, a recursive implementation can have a O(h) space complexity [worst case], where h is the maximal depth of your tree.
Using an iterative solution with a stack is actually the same as BFS, just using a stack instead of a queue - so you get both O(|V|) time and space complexity.
a
b e
c d f g
a
|
|--> b
| |
| |--> c
| |
| |--> d
|
|--> e
|
|--> f
|
|--> g
16.
Memoization vs Tabulation in Dynamic Programming
http://stackoverflow.com/questions/6184869/what-is-difference-between-memoization-and-dynamic-programming
What is the difference between tabulation (the typical dynamic programming technique) and memoization?
When you solve a dynamic programming problem using tabulation you solve the problem "bottom up",
i.e., by solving all related sub-problems first, typically by filling up an n-dimensional table.
Based on the results in the table, the solution to the "top" / original problem is then computed.
If you use memoization to solve the problem you do it by maintaining a map of already solved sub problems.
You do it "top down" in the sense that you solve the "top" problem first (which typically recurses down to solve the sub-problems).
A good slide from here (link is now dead, slide is still good though):
If all subproblems must be solved at least once, a bottom-up dynamic-programming algorithm usually outperforms a top-down memoized algorithm by a constant factor
No overhead for recursion and less overhead for maintaining table
There are some problems for which the regular pattern of table accesses in the dynamic-programming algorithm can be exploited to reduce the time or space requirements even further
If some subproblems in the subproblem space need not be solved at all, the memoized solution has the advantage of solving only those subproblems that are definitely required
17.
How to efficiently check whether it's height balanced for a massively skewed binary search tree
http://stackoverflow.com/questions/23160438/how-to-efficiently-check-whether-its-height-balanced-for-a-massively-skewed-bin
18.
How to determine if binary tree is balanced
http://stackoverflow.com/questions/742844/how-to-determine-if-binary-tree-is-balanced?lq=1
19.
Explain Morris inorder tree traversal without using stacks or recursion
http://stackoverflow.com/questions/5502916/explain-morris-inorder-tree-traversal-without-using-stacks-or-recursion
20.
Count subsequences divisible by K
http://stackoverflow.com/questions/24518682/count-subsequences-divisible-by-k
https://www.hackerrank.com/contests/w6/challenges/consecutive-subsequences/editorial
21.
Merge Overlapping intervals
http://www.geeksforgeeks.org/merging-intervals/
http://stackoverflow.com/questions/4542892/possible-interview-question-how-to-find-all-overlapping-intervals
http://stackoverflow.com/questions/15150188/amazon-interview-design-meeting-scheduler
22.
Finding all subsets of a Vector of Vector
http://stackoverflow.com/questions/728972/finding-all-the-subsets-of-a-set
It's very simple to do this recursively.
The basic idea is that for each element, the set of subsets can be divided equally into those that contain that element and those that don't, and those two sets are otherwise equal.
For n=1, the set of subsets is {{}, {1}}
For n>1, find the set of subsets of 1,...,n-1 and make two copies of it. For one of them, add n to each subset. Then take the union of the two copies.
Edit To make it crystal clear:
The set of subsets of {1} is {{}, {1}}
For {1, 2}, take {{}, {1}}, add 2 to each subset to get {{2}, {1, 2}} and take the union with {{}, {1}} to get {{}, {1}, {2}, {1, 2}}
Repeat till you reach n
23.
Converting Recursive Algorithm to Iterative
http://stackoverflow.com/questions/159590/way-to-go-from-recursion-to-iteration
http://programmers.stackexchange.com/questions/194646/what-methods-are-there-to-avoid-a-stack-overflow-in-a-recursive-algorithm
Usually, I replace a recursive algorithm by an iterative algorithm by pushing the parameters that would normally be passed to the recursive function onto a stack.
In fact, you are replacing the program stack by one of your own.
Stack<Object> stack;
stack.push(first_object);
while( !stack.isEmpty() ) {
// Do something
my_object = stack.pop();
// Push other objects on the stack.
}
Note: if you have more than one recursive call inside and you want to preserve the order of the calls, you have to add them in the reverse order to the stack:
foo(first);
foo(second);
has to be replaced by
stack.push(second);
stack.push(first);
24.
Balancing Binary Search Trees on a whole
http://stackoverflow.com/questions/14001676/balancing-a-bst
Day-Stout-Warren:
1. Using tree rotations, convert the tree into a degenerate linked list.
2. By applying selective rotations to the linked list, convert the list back into a completely balanced tree.
The solution is simple - build an "empty" complete binary tree, and iterate the new tree and the input tree (simultaneously) in inorder-traversal to fill the complete tree.
When you are done, you have the most balanced tree you can get, and time complexity of this approach is O(n)
24b.
Balancing Binary Search Trees after each insertion
How AVL trees gets self balanced
http://www.geeksforgeeks.org/avl-tree-set-1-insertion/
Left Rotation and Right Rotation
Following are two basic operations that can be performed to re-balance a BST without violating the BST property (keys(left) < key(root) < keys(right)).
1) Left Rotation
2) Right Rotation
T1, T2 and T3 are subtrees of the tree rooted with y (on left side)
or x (on right side)
y x
/ \ Right Rotation / \
x T3 --------------> T1 y
/ \ < - - - - - - - / \
T1 T2 Left Rotation T2 T3
Keys in both of the above trees follow the following order
keys(T1) < key(x) < keys(T2) < key(y) < keys(T3)
So BST property is not violated anywhere.
a) Left Left Case
T1, T2, T3 and T4 are subtrees.
z y
/ \ / \
y T4 Right Rotate (z) x z
/ \ - - - - - - - - -> / \ / \
x T3 T1 T2 T3 T4
/ \
T1 T2
b) Left Right Case
z z x
/ \ / \ / \
y T4 Left Rotate (y) x T4 Right Rotate(z) y z
/ \ - - - - - - - - -> / \ - - - - - - - -> / \ / \
T1 x y T3 T1 T2 T3 T4
/ \ / \
T2 T3 T1 T2
c) Right Right Case
z y
/ \ / \
T1 y Left Rotate(z) z x
/ \ - - - - - - - -> / \ / \
T2 x T1 T2 T3 T4
/ \
T3 T4
d) Right Left Case
z z x
/ \ / \ / \
T1 y Right Rotate (y) T1 x Left Rotate(z) z y
/ \ - - - - - - - - -> / \ - - - - - - - -> / \ / \
x T4 T2 y T1 T2 T3 T4
/ \ / \
T2 T3 T3 T4
24c.
B+ Tree vs Red Black Trees vs AVL trees
http://stackoverflow.com/questions/13852870/red-black-tree-over-avl-tree
http://stackoverflow.com/questions/1589556/when-to-choose-rb-tree-b-tree-or-avl-tree
- B-tree when you're managing more than thousands of items and you're paging them from a disk or some slow storage medium.
- RB tree when you're doing fairly frequent inserts, deletes and retrievals on the tree.
- AVL tree when your inserts and deletes are infrequent relative to your retrievals.
1. What's the main aim we are chossing Red black tree instead of Avl tree?
Both red-black trees and AVL trees are the most commonly used balanced binary search trees and they support insertion, deletion and look-up in guaranteed O(logN) time.
However, there are following points of comparison between the two:
1. AVL trees are more rigidly balanced and hence provide faster look-ups. Thus for a look-up intensive task use an AVL tree.
2. For an insert intensive taks, use a Red-Black tree.
3. AVL trees store the balance factor at each node.
This takes O(N) extra space.
However, if we know that the keys that will be inserted in the tree will always be greater than zero, we can use the sign bit of the keys to store the colour information of a red-black tree.
Thus, in such cases red-black tree takes O(1) extra space.
4. In general, the rotations for an AVL tree are harder to implement and debug than that for a Red-Black tree.
http://stackoverflow.com/questions/16257761/difference-between-red-black-trees-and-avl-trees
IMP:
- AVL trees maintain a more rigid balance than red-black trees.
- The path from the root to the deepest leaf in an AVL tree is at most ~1.44 lg(n+2), while in red black trees it's at most ~2 lg (n+1).
- As a result, lookup in an AVL tree is typically faster, but this comes at the cost of slower insertion and deletion due to more rotation operations.
- So use an AVL tree if you expect the number of lookups to dominate the number of updates to the tree.
2. What are the application of Red black tree?
Red-black trees are more general purpose.
They do relatively well on add, remove, and look-up but AVL trees have faster look-ups at the cost of slower add/remove.
Red-black tree is used in the following:
- Java: java.util.TreeMap , java.util.TreeSet .
- C++ STL: map, multimap, multiset.
- Linux kernel: completely fair scheduler, linux/rbtree.h
LARGE DATA vs SMALL DATA: AVL vs RB Tree:
For small data:
1. insert:
RB tree & avl tree has constant number of max rotation but RB tree will be faster because on average RB tree use less rotation.
2. lookup:
AVL tree is faster, because AVL tree has less depth.
3. delete:
RB tree has constant number of max rotation but AVL tree can have O(log N) times of rotation as worst. and on average RB tree also has less number of rotation thus RB tree is faster.
for large data:
1. insert:
AVL tree is faster. because you need to lookup for a particular node before insertion. as you have more data the time difference on looking up the particular node grows proportional to O(log N). but AVL tree & RB tree still only need constant number of rotation at the worst case. Thus the bottle neck will become the time you lookup for that particular node.
2. lookup:
AVL tree is faster. (same as in small data case)
3. delete:
AVL tree is faster on average, but in worst case RB tree is faster. because you also need to lookup for a very deep node to swap before removal (similar to the reason of insertion). on average both trees has constant number of rotation. but RB tree has a constant upper bound for rotation.
25.
Balancing a Heap
26.
Why is Heapify O(n)
http://stackoverflow.com/questions/9755721/how-can-building-a-heap-be-on-time-complexity
When heapify is called, the running time depends on how far an element might move down in tree before the process terminates.
In other words, it depends on the height of the element in the heap.
In the worst case, the element might go down all the way to the leaf level.
Let us count the work done level by level.
At the bottommost level, there are 2^(h)nodes, but we do not call heapify on any of these, so the work is 0.
At the next to level there are 2^(h - 1) nodes, and each might move down by 1 level.
At the 3rd level from the bottom, there are 2^(h - 2) nodes, and each might move down by 2 levels.
As you can see not all heapify operations are O(log n), this is why you are getting O(n)
26b.
SiftUp vs SiftDown
https://en.wikipedia.org/wiki/Heapsort
http://stackoverflow.com/questions/9755721/how-can-building-a-heap-be-on-time-complexity
https://www.youtube.com/watch?v=MiyLo8adrWw&feature=youtu.be
Heapify is O(n) when done with siftDown but O(n log n) when done with siftUp.
The actual sorting (pulling items from heap one by one) has to be done with siftUp so is therefore O(n log n)
- siftDown swaps a node that is too small with its largest child (thereby moving it down) until it is at least as large as both nodes below it.
- siftUp swaps a node that is too large with its parent (thereby moving it up) until it is no larger than the node above it.
The heapify procedure can be thought of as building a heap from the bottom up by successively sifting downward to establish the heap property.
An alternative version (shown below) that builds the heap top-down and sifts upward may be simpler to understand.
This siftUp version can be visualized as starting with an empty heap and successively inserting elements, whereas the siftDown version given above treats the entire input array as a full but "broken" heap and "repairs" it starting from the last non-trivial sub-heap (that is, the last parent node).
Also, the siftDown version of heapify has O(n) time complexity, while the siftUp version given below has O(n log n) time complexity due to its equivalence with inserting each element, one at a time, into an empty heap
SIFTUP:
- Insertion of a new element into a heap is done in two steps.
- First the element is inserted in the only place with room for it,- At the bottom of the tree, - And next it is shifted up the tree until the heap property holds.
- The insertion is trivial, but the siftup deserves extra attention because of its importance for the performance.
SIFTDOWN:
- Deletion of the maximum element from the heap must find an element to replace the maximum element (in the root).
- As for insertion this is done in to steps.
- First the maximum element (the root) is replaced with the last element of the heap, and next the new root is shifted down the tree along the path of the largest children.
The number of operations required for each operation is proportional to the distance the node may have to move.
For siftDown, it is the distance from the bottom of the tree, so siftDown is expensive for nodes at the top of the tree.
With siftUp, the work is proportional to the distance from the top of the tree, so siftUp is expensive for nodes at the bottom of the tree.
Although both operations are O(log n) in the worst case, in a heap, only one node is at the top whereas half the nodes lie in the bottom layer.
So it shouldn't be too surprising that if we have to apply an operation to every node, we would prefer siftDown over siftUp.
The buildHeap function takes an array of unsorted items and moves them until it they all satisfy the heap property.
There are two approaches one might take for buildHeap.
One is to start at the top of the heap (the beginning of the array) and call siftUp on each item.
At each step, the previously sifted items (the items before the current item in the array) form a valid heap, and sifting the next item up places it into a valid position in the heap.
After sifting up each node, all items satisfy the heap property.
The second approach goes in the opposite direction: start at the end of the array and move backwards towards the front. At each iteration, you sift an item down until it is in the correct location.
Both of these solutions will produce a valid heap. The question is: which implementation for buildHeap is more efficient? Unsurprisingly, it is the second operation that uses siftDown. If h = log n is the height, then the work required for the siftDown approach is given by the sum
(0 * n/2) + (1 * n/4) + (2 * n/8) + ... + (h * 1).
i.e. n/2 nodes might have to move 0 level
n/4 nodes might have to move 1 level
n/8 nodes might have to move 2 level
...
Each term in the sum has the maximum distance a node at the given height will have to move (zero for the bottom layer, h for the root) multiplied by the number of nodes at that height. In contrast, the sum for calling siftUp on each node is
(h * n/2) + ((h-1) * n/4) + ((h-2)*n/8) + ... + (0 * 1).
i.e. n/2 nodes might have to move h level
It should be clear that the second sum is larger. The first term alone is hn/2 = 1/2 n log n, so this approach has complexity at best O(n log n). However, the sum for the siftDown approach can be bounded by extending it to a Taylor series to show that it is indeed O(n). If there is interest, I can edit my answer to include the details. Obviously, O(n) is the best you could hope for.
27.
n way merge
https://www.geeksforgeeks.org/merge-k-sorted-arrays/
Create a min Heap and insert the first element of all k arrays.
Run a loop until the size of MinHeap is greater than zero.
Remove the top element of the MinHeap and print the element.
Now insert the next element from the same array in which the removed element belonged.
If the array doesn¿t have any more elements, then replace root with infinite.After replacing the root, heapify the tree.
28.
B Tree vs B+ Tree
http://stackoverflow.com/questions/870218/differences-between-b-trees-and-b-trees/12014474#12014474
The image below helps show the differences between B+ trees and B trees.