Time complexity of nested for loop with multiple if statements - time-complexity

What will be the ideal time complexity in such a situation?
For i in list1:
If i in list2:
If i not in list3:
i.append(list)
Thanks in advance

The time complexity depends on the implementation your data structures list1-3 and their content. Assuming you have a list that the you need to traverse completely to execute the x in list statements:
For i in list1: // O(n) where n is the length of list1
If i in list2: // O(n*m) where m is the length of list2
If i not in list3 // O(n*m*o) where o is the length of list3
Worst case any i in list2 is true will result in O(n*m*o) independent if i is on list3 or not, because you have to check the complete list3 in any way and the additional of the depending If is constant.
Best case any i in list2 is false will result in O(n*m) as you don't have to execute any code of the list3 iteration.

Related

How can I improve Insertionsort by the following argument ? The correct answer is b. Can someone CLEARLY explain every answer?

A person claims that they can improve InsertionSort by the following argument. In the innermost loop of InsertionSort, instead of looping over all entries in the already sorted array in order to insert the j’th observed element, simply perform BinarySearch in order to sandwich the j’th element in its correct position in the list A[1, ... , j−1]. This person claims that their resulting insertion sort is asymptotically as good as mergesort in the worst case scenario. True or False and why? Circle the one correct answer from the below:
a. True: In this version, the while loop will iterate log(n), but in each such iteration elements in the left side of the list have to be shifted to allow room for the key to propagate downwards across the median elements and so this shift will still require log(n) in the worst case scenario. Adding up, Insertion Sort will significantly improve in this case to continue to require n log(n) in the worst case scenario like mergesort.
b. False: In this version, the while loop will iterate log(n), but in each such iteration elements in the left side of the list have to be shifted to allow room for the key to propagate downwards and so this shift will still require n in the worst case scenario. Adding up, Insertion Sort will continue to require n² in the worst case scenario which is orders of magnitude worse than mergesort.
c. False: In this version, the while loop will iterate n, but in each such iteration elements in the left side of the list have to be shifted to allow room for the key to propagate downwards and so this shift will still require log(n) in the worst case scenario. Adding up, Insertion Sort will continue to require n log(n) in the worst case scenario which is orders of magnitude worse than mergesort.
d. True: In this version, the while loop will iterate log(n), but in each such iteration elements in the left side of the list have to be shifted to allow room for the key to propagate downwards and so this shift will still require n in the worst case scenario. Adding up, Insertion Sort will continue to require n log(n) in the worst case scenario which is orders of magnitude worse than mergesort.
b is correct, with some assumptions about compiler optimizations.
Consider a reverse sorted array,
8 7 6 5 4 3 2 1
and that insertion sort is half done so it is
5 6 7 8 4 3 2 1
The next step:
normal insertion sort sequence assuming most recent value read kept in register:
t = a[4] = 4 1 read
compare t and a[3] 1 read
a[4] = a[3] = 8 1 write
compare t and a[2] 1 read
a[3] = a[2] = 7 1 write
compare t and a[1] 1 read
a[2] = a[1] = 6 1 write
compare t and a[0] 1 read
a[1] = a[0] = 5 1 write
a[0] = t = 4 1 write
---------------
5 read 5 write
binary search
t = a[4] 1 read
compare t and a[1] 1 read
compare t and a[0] 1 read
a[4] = a[3] 1 read 1 write
a[3] = a[2] 1 read 1 write
a[2] = a[1] 1 read 1 write
a[1] = a[0] 1 read 1 write
a[0] = t 1 write
----------------
7 read 5 write
If a compiler re-read data with normal insertion sort it would be
9 read 5 write
In which case the binary search would save some time.
The expected answer to this question is b), but the explanation is not precise enough:
locating the position where to insert the j-th element indeed requires log(j) comparisons instead of j comparisons for regular Insertion Sort.
inserting the elements requires j element moves in the worst case for both implementations (reverse sorted array).
Summing these over the whole array produces:
n log(n) comparisons for this modified Insertion Sort idea in all cases vs: n2 comparisons in the worst case (already sorted array) for the classic implementation.
n2 element moves in the worst case in both implementations (reverse sorted array).
note that in the classic implementation the sum of the number of comparisons and element moves is constant.
Merge Sort on the other hand uses approximately n log(n) comparisons and n log(n) element moves in all cases.
Therefore the claim the resulting insertion sort is asymptotically as good as mergesort in the worst case scenario is False, indeed because the modified Insertion Sort method still performs n2 element moves in the worst case, which is asymptotically much worse than n log(n) moves.
Note however that depending on the relative cost of comparisons and element moves, the performance of this modified Insertion Sort approach may be much better than the classic implementation, for example sorting an array of string pointers containing URLs to the same site, the cost of comparing strings with a long initial substring is much greater than moving a single pointer.

How to get guaranteed unique list shuffles in Kotlin

I have a list of nine numbers (1-9), that I need to shuffle based on a seed, and guarantee that each permutation of that shuffle is unique. I'd like to do that like this:
list.shuffle(Random(seed))
There are 9! (362,880) possible permutations of this list, and I know that if I pass it the same Random seed twice, those two permutations will be identical, but I need a way to guarantee that for any given seed between 0 and 362,880, the list order will be unique from any other seed in that range.
Is this possible in Kotlin?
This isn't really a question about Kotlin, but algorithms in general.
There could be much better solution, but you can represent your seed as a number with variable base. First digit has base of 9, second has base of 8 and so on. When dealing with numbers of base 10, we need to repeatedly divide it by 10 and note the remainder to split it into digits. In our case we need to divide it by 9, 8, 7 and so on. This way we will convert the seed to a list of 9 digits like this: 0-8, 0-7, 0-6, ... . What is important: each seed has a unique list of such digits.
Now, if we create another list of numbers 1-9, then we can use the list of digits from the previous paragraph to pick numbers from it, removing them at the same time. Initially, we have 9 items in our list, so valid indexes are 0-8 and this is exactly the range of our first digit. Then we have only 8 remaining items, so they have indexes 0-7 and this is exactly what the second digit is. And so on.
This is not that easy to explain in words, code could be better:
fun shuffled1to9(seed: Int): List<Int> {
require(seed in 0 until 362880)
val remaining = (1..9).toMutableList()
val result = mutableListOf<Int>()
var curr = seed
(9 downTo 2).forEach {
val (next, pick) = curr divmod it
result += remaining.removeAt(pick)
curr = next
}
result += remaining.single()
return result
}
infix fun Int.divmod(divisor: Int): Pair<Int, Int> {
val quotient = this / divisor
return quotient to (this - quotient * divisor)
}
shuffled1to9(0) returns original order of 1..9. shuffled1to9(362879) returns the order inverted: 9..1. Any number in between should generate a unique ordering.
Of course, it can be very easily generalized to different lists of numbers and to different sizes.

Is the time complexity of the following cases correct?

I am a bit confused about the (average case) time complexity of the following cases:
I have N=3 arrays, each with different number of elements:
Array1 has n1 elements
Array2 has n2 elements
Array3 has n3 elements
Case A: I perform quicksort on each array in a sequential manner, starting from the first array till the last.
In this case the time complexity will be N*O(nlogn) (where n is the generalized form of the number of elements of an array) or O(n1logn1 + n2logn2 + n3logn3), which asymptotically is equal to O(max(n1logn1, n2logn2, n3logn3))?
Case B: I perform quicksort on each array in parallel.
In this case the time complexity will be O(max(n1logn1, n2logn2, n3logn3))?
Case C: There is a 50% chance of performing quicksort (on all arrays, in parallel) and 50% chance of not sorting any array.
Isn't this case essentially the same as case B? I.e. 0.5 * O(max(n1logn1, n2logn2, n3logn3)), which asymptotically is equal to O(max(n1logn1, n2logn2, n3logn3))?
Therefore, all cases have the same time complexity, O(max(n1logn1, n2logn2, n3logn3))?

What is one of the more efficient ways to search for a string in an array and get its index?

Given an enum similar to this:
Friend Enum TestValue As Int32
tstNotSet = -1
tstA = 0
tstB = 1
tstC = 2
tstD = 3
tstE = 4
tstF = 5
tstG = 6
tstH = 7
tstI = 8
tstJ = 9
tstK = 10
tstL = 11
tstM = 12
End Enum
And an Array similar to this:
Dim TestValues() As String = {"A", "B", "C", "D", "E", "F", "G",
"H", "I", "J", "K", "L", "M"}
And a string is fed in as input in some form similar to (assume it is already stored to a variable):
Dim tmpInput As String = "ADFGHJLM"
And a Sub/Method in another arbitrary class that takes in as input an array of one of more of the Enums from TestValue, based on the input string tmpInput. Basically, I want to walk the tmpInput variable, and for each character, map out its equivalent member in the Enum, so that I can pass it to this Sub in the other object. The string array TestValues and the Enum TestValue (yes, the names could be done better, but don't let that bother you too much) are laid out to match each other explicitly.
So I basically want to search the array for the matching letter, and use its index offset to know which Enum I want to map to that letter. My current code uses a large Select Case statement, but that's just ugly (although, performance tests show it to be rather speedy, even in the debug build).
The purpose of this test case is to provide an example of a mechanism I use in a project I'm working on. In this project, objects have a ReadOnly property that returns a string of letters composed from TestValues. It also has a Sub that accepts an array of one or more Enums from TestValue that sets a private member in the object that is used by the aforementioned ReadOnly property. The purpose was to store an array of smaller integer values (the Enums) rather than an array of strings for the object's internal functionality. So I had to create a way to map back and forth between the string array and the enum.
Yes, it's easily doable with the many different collections available in .NET, but I feel those are too heavyweight for my needs, as many of my objects have enums as small as two values, hence, arrays. I borrowed the trick from a similar example used in C to be able to select a string from a const array based on an index offset.
Anyways, as I've discovered, searching arrays in VB.NET is not trivial. There is apparently no simple command like TestValues.GetIndex(tmp(i)), where tmp(i) is a variable holding a single character (String, not Char), that would return say, '8' if tmp(i) was set to 'I'. Instead, methods like Array.FindIndex require using delegates/predicates, something I haven't fully wrapped my head around just yet (they seem like function pointers from C).
So what's the best way, other than constantly looping over the array for every input character, to locate the index offset based on the stored value? Is the method I highlight sane or insane (hint: it's a hold-over from VBA code)? Is there a more efficient way?
Oh, and yes, the ReadOnly property does check that the internal members are NOT set to tstNotSet before attempting to read from the TestValues array. That's why that Enum member exists.
Thanks!
EDIT: Hopefully this doesn't muddle the explanation up too much, but here's an example, as simplified as I can get it, of how the look up currently operates using the array, enum, and input string as defined above:
Dim n As Int32 = 0
Dim Foobar(0 to 12) As TestValue
For Each s As String In tmpInput
Select Case Char.ToUpper(CChar(s))
Case CChar(TestValues(tstA))
Foobar(n) = tstA
n += 1
Case CChar(TestValues(tstB))
Foobar(n) = tstB
n += 1
Case CChar(TestValues(tstC))
Foobar(n) = tstC
n += 1
Case CChar(TestValues(tstD))
Foobar(n) = tstD
n += 1
Case CChar(TestValues(tstE))
Foobar(n) = tstE
n += 1
Case CChar(TestValues(tstF))
Foobar(n) = tstF
n += 1
Case CChar(TestValues(tstG))
Foobar(n) = tstG
n += 1
Case CChar(TestValues(tstH))
Foobar(n) = tstH
n += 1
Case CChar(TestValues(tstI))
Foobar(n) = tstI
n += 1
Case CChar(TestValues(tstJ))
Foobar(n) = tstJ
n += 1
Case CChar(TestValues(tstK))
Foobar(n) = tstK
n += 1
Case CChar(TestValues(tstL))
Foobar(n) = tstL
n += 1
Case CChar(TestValues(tstM))
Foobar(n) = tstM
n += 1
End Select
Next
As noted in my comment to Jon Skeet, this construct, along with the rest of the Object's components, executes 100,000 times in a profiling loop in ~570ms (rough average of 3-5 runs).
Exchanging the above construct out with a smaller Array.IndexOf construct loops 100,000 times in ~630ms (again, 3-5 runs, rough average, the whole Object). The new construct looks like this:
Dim p As Int32
p = Array.IndexOf(TestValues, s)
If p <> tstNotSet Then
Foobar(n) = DirectCast(p, TestValue)
n += 1
End If
I'm afraid I found your question extremely hard to understand, but is Array.IndexOf what you're looking for?
Dim index = Array.IndexOf(TestValues, tmp(i))
I've got trouble tying a rope to this question. But in any kind of lookup scenario, you always want to use a Dictionary. You'll get O(1) time instead of O(n). Something like this:
Dim lookup As New Dictionary(Of Char, TestValue)
lookup.Add("A"c, TestValue.tstA)
lookup.Add("B"c, TestValue.tstB)
'' etc
You can make the initialization cleaner in many ways. Then:
Dim value As TestValue = lookup(letter)
i would say the solution by #Hans Passant is the way to go with this, but since you are dealing with chars, and chars are numbers,there is an alternative where you dont need a Dictionary.
you could store all the TestValue enum values in an array, and do something like testValueResult = testValueArray(charCode - 65),i.e. just map 'A' to index 0,'B' to 1..., or even just a direct cast from the numeric form of the TestValue to its Enum since you do define it as an integer, and include a simple bounds check for tstNotSet too.

VB.NET Array Intersection

This could be terribly trivial, but I'm having trouble finding an answer that executes in less than n^2 time. Let's say I have two string arrays and I want to know which strings exist in both arrays. How would I do that, efficiently, in VB.NET or is there a way to do this other than a double loop?
The simple way (assuming no .NET 3.5) is to dump the strings from one array in a hashtable, and then loop through the other array checking against the hashtable. That should be much faster than an n^2 search.
If you sort both arrays, you can then walk through them each once to find all the matching strings.
Pseudo-code:
while(index1 < list1.Length && index2 < list2.Length)
{
if(list1[index1] == list2[index2])
{
// You've found a match
index1++;
index2++;
} else if(list1[index1] < list2[index2]) {
index1++;
} else {
index2++;
}
}
Then you've reduced it to the time it takes to do the sorting.
If one of the arrays is sorted you can do a binary search on it in the inner loop, this will decrease the time to O(n log n)
Sort both lists. Then you can know with certainty that if the next entry in list A is 'cobble' and the next entry in list B is 'definite', then 'cobble' is not in list B. Simply advance the pointer/counter on whichever list has the lower ranked result and ascend the rankings.
For example:
List 1: D,B,M,A,I
List 2: I,A,P,N,D,G
sorted:
List 1: A,B,D,I,M
List 2: A,D,G,I,N,P
A vs A --> match, store A, advance both
B vs D --> B
D vs D --> match, store D, advance both
I vs G --> I>G, advance 2
I vs I --> match, store I, advance both
M vs N --> M
List 1 has no more items, quit.
List of matches is A,D,I
2 list sorts O(n log(n)), plus O(n) comparisons makes this O(n(log(n) + 1)).