Using built in methods, one can access the element at index i of a string by using:
let s = "string"
s[advance(s.startIndex,i)]
However, if i is out of range this results in a runtime error. Is there a built in way to achieve this and get it to return nil if the index is out of range? Seeing as optional chaining exists for just about everything, I'd expect this to be available.
There is – there’s a second version of advance that takes a third parameter, an index not to go beyond:
let s = "string"
let idx = advance(s.startIndex, i, s.endIndex)
Unfortunately it’s a bit more fiddly than your hoped-for usage. If you do this:
let s = "string"
let idx = advance(s.startIndex, 10, s.endIndex)
then you’ll still get a runtime error, because endIndex isn’t a valid index for subscript.
You have two choices, both of which involve an extra check. Either check idx != s.endIndex. Or check !s.isEmpty then if not, do s[advance(s.startIndex, i, s.endIndex.predecessor())].
(you have to check the string isn’t empty here for two reasons – one is if it is, no subscript is valid, and the other is if startIndex == endIndex then endIndex.predecessor() isn’t valid)
Finally, beware putting calls to advance from startIndex like this in a loop. advance from a point is not a constant-time operation, it’s linear. So if you call it in a loop over the string length, your algorithm will be quadratic. If you need to walk the string, best to do it by continuously incrementing an index or even better using a higher-level function like map or filter.
Related
I am implementing the merge sort algorithm in Python. Previously, I have implemented the same algorithm in C, it works fine there, but when I implement in Python, it outputs an unsorted array.
I've already rechecked the algorithm and code, but to my knowledge the code seems to be correct.
I think the issue is related to the scope of variables in Python, but I don't have any clue for how to solve it.
from random import shuffle
# Function to merge the arrays
def merge(a,beg,mid,end):
i = beg
j = mid+1
temp = []
while(i<=mid and j<=end):
if(a[i]<a[j]):
temp.append(a[i])
i += 1
else:
temp.append(a[j])
j += 1
if(i>mid):
while(j<=end):
temp.append(a[j])
j += 1
elif(j>end):
while(i<=mid):
temp.append(a[i])
i += 1
return temp
# Function to divide the arrays recursively
def merge_sort(a,beg,end):
if(beg<end):
mid = int((beg+end)/2)
merge_sort(a,beg,mid)
merge_sort(a,mid+1,end)
a = merge(a,beg,mid,end)
return a
a = [i for i in range(10)]
shuffle(a)
n = len(a)
a = merge_sort(a, 0, n-1)
print(a)
To make it work you need to change merge_sort declaration slightly:
def merge_sort(a,beg,end):
if(beg<end):
mid = int((beg+end)/2)
merge_sort(a,beg,mid)
merge_sort(a,mid+1,end)
a[beg:end+1] = merge(a,beg,mid,end) # < this line changed
return a
Why:
temp is constructed to be no longer than end-beg+1, but a is the initial full array, if you managed to replace all of it, it'd get borked quick. Therefore we take a "slice" of a and replace values in that slice.
Why not:
Your a luckily was not getting replaced, because of Python's inner workings, that is a bit tricky to explain but I'll try.
Every variable in Python is a reference. a is a reference to a list of variables a[i], which are in turn references to a constantant in memory.
When you pass a to a function it makes a new local variable a that points to the same list of variables. That means when you reassign it as a=*** it only changes where a points. You can only pass changes outside either via "slices" or via return statement
Why "slices" work:
Slices are tricky. As I said a points to an array of other variables (basically a[i]), that in turn are references to a constant data in memory, and when you reassign a slice it goes trough the slice element by element and changes where those individual variables are pointing, but as a inside and outside are still pointing to same old elements the changes go through.
Hope it makes sense.
You don't use the results of the recursive merges, so you essentially report the result of the merge of the two unsorted halves.
I am having trouble with the second function in converting it back to the original string. I see what the issue is as when I call previous function, the tuple has a string and an int. So I assume I must convert that int to a string. But based on the code I wrote, I am not sure where to convert it. Hopefully, I am on the right track with this. My professor is very strict when it comes to certain things I cannot use any built-ins. Thank you. Any help is appreciated.
EDIT
Will put code back soon
My suggestion is in this case to use print statements for debugging.
def rldecode(rlencode):
decodedString = ""
L = []
for i in rlencode:
counter = 0
occurrence = i[1] # tuple (item, occurrence) == positions (0, 1)
for j in range(occurrence):
L.append(i[0])
return ''.join(L)
During an interview, I was asked the time complexity of the following algorithm:
static bool SetContainsString(string searchString, HashSet<string> setOfStrings)
{
for (int i = 0; i < searchString.Length; i++)
{
var segment = searchString.Substring(0, i + 1);
if (setOfStrings.Contains(segment))
{
var remainingSegment = searchString.Substring(segment.Length);
if (remainingSegment == "") return true;
return SetContainsString(remainingSegment, setOfStrings);
}
}
return false;
}
I answered "linear" because it appears to me to loop only through the length of searchString. Yes, it is recursive, but the recursive call is only on the portion of the string that has not yet been iterated over, so the end result number of iterations is the length of the string.
I was told by my interviewer that the time complexity in the worst case is exponential.
Can anyone help me clarify this? If I am wrong, I need to understand why.
I believe that your interviewer was incorrect here. Here’s how I’d argue why the time complexity isn’t exponential:
Each call to the function either makes zero or one recursive call.
Each recursive call reduces the length of the string by at least one.
This bounds the total number of recursive calls at O(n), where n is the length of the input string. Each individual recursive call does a polynomial amount of work, so the total work done is some polynomial.
I think the reason your interviewer was confused here is that the code given above - which I think is supposed to check if a string can be decomposed into one or more words - doesn’t work correctly in all cases. In particular, notice that the recursion works by always optimistically grabbing the first prefix it finds that’s a word and assuming that what it grabbed is the right way to split the word apart. But imagine you have a word like “applesauce.” If you pull off “a” and try to recursively form “pplesauce,” you’ll incorrectly report that the word isn’t a compound because theres no way to decompose “pplesauce.” To fix this, you’d need to change the recursive call to something like this:
if (SetContainsString(...)) return true;
This way, if you pick the wrong split, you’ll go on to check the other possible splits you can make. That variant on the code does take exponential time in the worst case because it can potentially revisit the same substrings multiple times, and I think that’s what the interviewer incorrectly thought you were doing.
i am doing a homework assignment where I have to check large lists of numbers for a given number. the list length is <= 20000, and I can be searching for just as many numbers. if the number we are searching for is in the list, return the index of that number, otherwise, return -1. here is what I did.
i wrote the following code, that outputsthe correct answer, but does not do it fast enough. it has to be done in less than 1 second.
here is my binary search code:`I am looking for suggestions to make it faster.
def binary_search(list1, target):
p = list1
upper = len(list1)
lower = 0
found = False
check = int((upper+lower)//2)
while found == False:
upper = len(list1)
lower = 0
check = int(len(list1)//2)
if list1[check] > target:
list1 = list1[lower:check]
check= int((len(list1))//2)
if list1[check] < target:
list1 = list1[check:upper]
check = int((len(list1))//2)
if list1[check] == target:
found = True
return p.index(target)
if len(list1)==1:
if target not in list1:
return -1`
grateful for any help/
The core problem is that this is not a correctly written Binary Search (see the algorithm there).
There is no need of index(target) to find the solution; a binary search is O(lg n) and so the very presence of index-of, being O(n), violates this! As written, the entire "binary search" function could be replaced as list1.index(value) as it is "finding" the value index simply to "find" the value index.
The code is also slicing the lists which is not needed1; simply move the upper/lower indices to "hone in" on the value. The index of the found value is where the upper and lower bounds eventually meet.
Also, make sure that list1 is really a list such that the item access is O(1).
(And int is not needed with //.)
1 I believe that the complexity is still O(lg n) with the slice, but it is a non-idiomatic binary search and adds additional overhead of creating new lists and copying the relevant items. It also doesn't allow the correct generation of the found item's index - at least without similar variable maintenance as found in a traditional implementation.
Try using else if's, for example if the value thats being checked is greater then you don't also need to check if its smaller.
I am doing an application where I want to find a specific char in an array of chars. In other words, I have the following char array:
char[] charArray= new char[] {'\uE001', '\uE002', '\uE003', '\uE004', '\uE005', '\uE006', '\uE007', '\uE008', '\uE009'};
At some point, I want to check if the character '\uE002' exists in the charArray. My method was to make a loop on every character in the charArray and find if it exists.
for (int z = 0 ; z < charArray; z ++) {
if (charArray[z] == myChar) {
//Do the work
}
}
Is there any other solution than making a char array and finding the character by looping every single char?
One option is to pre-sort charArray and use Arrays.binarySearch(charArray, myChar). A non-negative return value will indicate that myChar is present in charArray.
char[] charArray = new char[] {'\uE001', '\uE002', '\uE003', '\uE004', '\uE005', '\uE006', '\uE007', '\uE008', '\uE009'};
Arrays.sort(charArray); // can be omitted if you know that the values are already sorted
...
if (Arrays.binarySearch(charArray, myChar) >= 0) {
// Do the work
}
edit An alternative that avoids using the Arrays module is to put the characters into a string (at initialization time) and then use String.indexOf():
String chars = "\uE001...";
...
if (chars.indexOf(myChar) >= 0) {
// Do the work
}
This is not hugely different to what you're doing already, except that it requires less code.
If n is the size of charArray, the first solution is O(log n) whereas the second one is O(n).
You can use hash/map to check existance of the characer. This approach has better time of O(log n) or O(1) depending on hash/map inner structure.
If you don't have access to Arrays, since you are working in JavaME, then you should try to:
Or implement a sorted array and the binary search youself
Or just use a O(n) solution, wich is a good solution anyways.
Your solution is O(n), along with the one stated by aix.
You could try to use a Map, but it would depends on how much elements you are in your array. If you think there won't be more than 1000 elements in the array, just use a O(n) solution. But if you think you could have an unkown number of elements, a Map would be a reasoable choice, providing a better solution.
You can use net.rim.device.api.util.Arrays.getIndex(char[] array, char element)
It depends on what Java ME configuration / profile you are using. If you're on CDC then check for what parts of Java SE 1.3 Collections framework are supported (just find javadocs targeted for your device and look in java.util package). Another thing worth checking is whether your device has some blackberry-specific API extensions to work with collections.
If you are limited to bare minimum of CLDC/MIDP then other solution than you mentioned would be to add chars to Vector and use Vector.contains(Object)
If you don't want to implement it yourself you could use ArrayUtils in apache commons project:
ArrayUtils apache-commons