Runtime for binary search - python-3.x

New to algorithms
Trying a Binary Search problem, below is my code -
def search(nums, target):
low = 0
high = len(nums) - 1
#a = sorted(nums) --> to sort the list if needed [ change nums to a ]
while low <= high:
middle = (low + high) // 2
if target == nums[middle]:
return middle
elif target > nums[middle]:
low = middle + 1
else:
high = middle - 1
else:
return -1
Code is running fine with a runtime of 402 ms. Then I checked the code of other people and one of them had
middle = low + (high - low) // 2
and their runtime is 110 ms. Can someone please explain why such a difference is there between the runtime?

Related

How to create a watchdog on a program in python?

I want to know is it even possible to create a watchdog on a program,
I am trying to do Discrete event simulation to simulate a functioning machine,
the problem is, once I inspect my machine at let's say time = 12 (inspection duration is 2 hours lets say) if the event failure is at 13-time units) there is no way that it can be because I am "busy inspecting"
so is there a sort of "watchdog" to constantly test if the value of a variable reached a certain limit to stop doing what the program is doing,
Here is my inspection program
def machine_inspection(tt, R, Dpmi, Dinv, FA, TRF0, Tswitch, Trfn):
End = 0
TPM = 0
logging.debug(' cycle time %f' % tt)
TRF0 = TRF0 - Dinv
Tswitch = Tswitch - Dinv
Trfn = Trfn - Dinv
if R == 0:
if falsealarm == 1:
FA += 1
else:
tt = tt + Dpmi
TPM = 1
End = 1
return (tt, End, R, TPM, FA, TRF0, Trfn, Tswitch)
Thank you very much!
basically you can't be inspecting during x time if tt + x will be superior to the time to failure TRF0 or Trfn

SPIN assert not triggered

I am trying to understand why the assert in this model isn't triggered.
ltl { !A#wa U B#sb && !B#wb U A#sa }
byte p = 0
byte q = 0
int x = 0
inline signal(sem) { sem++ }
inline wait (sem) { atomic { sem > 0 ; sem-- } }
proctype A() {
x = 10*x + 1
signal(p)
sa: wait(q)
wa: x = 10*x + 2
}
proctype B() {
x = 10*x + 3
signal(q)
sb: wait(p)
wb: x = 10*x + 4
}
init {
atomic { run A(); run B() }
_nr_pr == 1
assert(x != 1324)
}
Clearly, there is an order of operations that produces the final value x = 1324:
Initially x = 0
A sets x = 10*0 + 1 = 1
B sets x = 10*1 + 3 = 13
A and B allow each other to proceed
A sets x = 10*13 + 2 = 132
B sets x = 10*132 + 4 = 1324
The assertion isn't triggered because it is "never reached" when the solver proves that the property
ltl { !A#wa U B#sb && !B#wb U A#sa }
is true.
Take a look at the output that is given by the solver, it clearly states that:
it is checking any assertion, but only if within the scope of the claim:
Full statespace search for:
never claim + (ltl_0)
assertion violations + (if within scope of claim)
the assertion isn't reached:
unreached in init
t.pml:27, state 5, "assert((x!=1324))"
t.pml:28, state 6, "-end-"
(2 of 6 states)
You can use the option -noclaim so to check the model only for the assertion, which is then easily proven false:
~$ spin -search -noclaim t.pml
ltl ltl_0: ((! ((A#wa))) U ((B#sb))) && ((! ((B#wb))) U ((A#sa)))
pan:1: assertion violated (x!=1324) (at depth 13)
pan: wrote t.pml.trail
(Spin Version 6.4.8 -- 2 March 2018)
Warning: Search not completed
+ Partial Order Reduction
Full statespace search for:
never claim - (not selected)
assertion violations +
cycle checks - (disabled by -DSAFETY)
invalid end states +
State-vector 36 byte, depth reached 15, errors: 1
48 states, stored
6 states, matched
54 transitions (= stored+matched)
1 atomic steps
hash conflicts: 0 (resolved)
Stats on memory usage (in Megabytes):
0.003 equivalent memory usage for states (stored*(State-vector + overhead))
0.286 actual memory usage for states
128.000 memory used for hash table (-w24)
0.534 memory used for DFS stack (-m10000)
128.730 total actual memory usage
pan: elapsed time 0 seconds

Python 3: How to exit loop without stopping function

I am a complete newbie and have tried solving this problem (with my own head and with online research) for the last 5 hours.
Below is a snippet of a function we have written to simulate a game. We want to offer the ooportunity to start a new round - meaning if a player hits "b", the game should start again at the beginning of the range (0, players). But right now it just goes onto the next player in the range (if player 1 enters "b", the program calls player 2)
players = input(4)
if players in range(3, 9):
for player in range(0, players):
sum_points = 0
throw_per_player_counter = 0
print("\nIt is player no.", player+1, "'s turn!\n")
print("\nPress 'return' to roll the dice.\n"
"To start a new round press 'b'.\n"
"Player", player+1)
roll_dice = input(">>> ")
if roll_dice == "b":
player = 0
throw_per_player_counter = 0
sum_points = 0
print("\n * A new round was started. * \n")
I have tried return and break, also tried to put it all in another while-loop... failed. Break and return just ended the function.
Any hints highly appreciated!
you could change the for loop to a while loop. instead of using a range, make player a counter
players = 4
if 3 <= players < 9:
player = 0 # here's where you make your counter
while player < players:
sum_points = 0
throw_per_player_counter = 0
print("\nIt is player no.", player+1, "'s turn!\n")
print("\nPress 'return' to roll the dice.\n"
"To start a new round press 'b'.\n"
"Player", player+1)
roll_dice = input(">>> ")
player += 1 # increment it
if roll_dice == "b":
player = 0 # now your reset should work
throw_per_player_counter = 0
sum_points = 0
print("\n * A new round was started. * \n")

How to find the lexicographically smallest string by reversing a substring?

I have a string S which consists of a's and b's. Perform the below operation once. Objective is to obtain the lexicographically smallest string.
Operation: Reverse exactly one substring of S
e.g.
if S = abab then Output = aabb (reverse ba of string S)
if S = abba then Output = aabb (reverse bba of string S)
My approach
Case 1: If all characters of the input string are same then output will be the string itself.
Case 2: if S is of the form aaaaaaa....bbbbbb.... then answer will be S itself.
otherwise: Find the first occurence of b in S say the position is i. String S will look like
aa...bbb...aaaa...bbbb....aaaa....bbbb....aaaaa...
|
i
In order to obtain the lexicographically smallest string the substring that will be reversed starts from index i. See below for possible ending j.
aa...bbb...aaaa...bbbb....aaaa....bbbb....aaaaa...
| | | |
i j j j
Reverse substring S[i:j] for every j and find the smallest string.
The complexity of the algorithm will be O(|S|*|S|) where |S| is the length of the string.
Is there a better way to solve this problem? Probably O(|S|) solution.
What I am thinking if we can pick the correct j in linear time then we are done. We will pick that j where number of a's is maximum. If there is one maximum then we solved the problem but what if it's not the case? I have tried a lot. Please help.
So, I came up with an algorithm, that seems to be more efficient that O(|S|^2), but I'm not quite sure of it's complexity. Here's a rough outline:
Strip of the leading a's, storing in variable start.
Group the rest of the string into letter chunks.
Find the indices of the groups with the longest sequences of a's.
If only one index remains, proceed to 10.
Filter these indices so that the length of the [first] group of b's after reversal is at a minimum.
If only one index remains, proceed to 10.
Filter these indices so that the length of the [first] group of a's (not including the leading a's) after reversal is at a minimum.
If only one index remains, proceed to 10.
Go back to 5, except inspect the [second/third/...] groups of a's and b's this time.
Return start, plus the reversed groups up to index, plus the remaining groups.
Since any substring that is being reversed begins with a b and ends in an a, no two hypothesized reversals are palindromes and thus two reversals will not result in the same output, guaranteeing that there is a unique optimal solution and that the algorithm will terminate.
My intuition says this approach of probably O(log(|S|)*|S|), but I'm not too sure. An example implementation (not a very good one albeit) in Python is provided below.
from itertools import groupby
def get_next_bs(i, groups, off):
d = 1 + 2*off
before_bs = len(groups[i-d]) if i >= d else 0
after_bs = len(groups[i+d]) if i <= d and len(groups) > i + d else 0
return before_bs + after_bs
def get_next_as(i, groups, off):
d = 2*(off + 1)
return len(groups[d+1]) if i < d else len(groups[i-d])
def maximal_reversal(s):
# example input: 'aabaababbaababbaabbbaa'
first_b = s.find('b')
start, rest = s[:first_b], s[first_b:]
# 'aa', 'baababbaababbaabbbaa'
groups = [''.join(g) for _, g in groupby(rest)]
# ['b', 'aa', 'b', 'a', 'bb', 'aa', 'b', 'a', 'bb', 'aa', 'bbb', 'aa']
try:
max_length = max(len(g) for g in groups if g[0] == 'a')
except ValueError:
return s # no a's after the start, no reversal needed
indices = [i for i, g in enumerate(groups) if g[0] == 'a' and len(g) == max_length]
# [1, 5, 9, 11]
off = 0
while len(indices) > 1:
min_bs = min(get_next_bs(i, groups, off) for i in indices)
indices = [i for i in indices if get_next_bs(i, groups, off) == min_bs]
# off 0: [1, 5, 9], off 1: [5, 9], off 2: [9]
if len(indices) == 1:
break
max_as = max(get_next_as(i, groups, off) for i in indices)
indices = [i for i in indices if get_next_as(i, groups, off) == max_as]
# off 0: [1, 5, 9], off 1: [5, 9]
off += 1
i = indices[0]
groups[:i+1] = groups[:i+1][::-1]
return start + ''.join(groups)
# 'aaaabbabaabbabaabbbbaa'
TL;DR: Here's an algorithm that only iterates over the string once (with O(|S|)-ish complexity for limited string lengths). The example with which I explain it below is a bit long-winded, but the algorithm is really quite simple:
Iterate over the string, and update its value interpreted as a reverse (lsb-to-msb) binary number.
If you find the last zero of a sequence of zeros that is longer than the current maximum, store the current position, and the current reverse value. From then on, also update this value, interpreting the rest of the string as a forward (msb-to-lsb) binary number.
If you find the last zero of a sequence of zeros that is as long as the current maximum, compare the current reverse value with the current value of the stored end-point; if it is smaller, replace the end-point with the current position.
So you're basically comparing the value of the string if it were reversed up to the current point, with the value of the string if it were only reversed up to a (so-far) optimal point, and updating this optimal point on-the-fly.
Here's a quick code example; it could undoubtedly be coded more elegantly:
function reverseSubsequence(str) {
var reverse = 0, max = 0, first, last, value, len = 0, unit = 1;
for (var pos = 0; pos < str.length; pos++) {
var digit = str.charCodeAt(pos) - 97; // read next digit
if (digit == 0) {
if (first == undefined) continue; // skip leading zeros
if (++len > max || len == max && reverse < value) { // better endpoint found
max = len;
last = pos;
value = reverse;
}
} else {
if (first == undefined) first = pos; // end of leading zeros
len = 0;
}
reverse += unit * digit; // update reverse value
unit <<= 1;
value = value * 2 + digit; // update endpoint value
}
return {from: first || 0, to: last || 0};
}
var result = reverseSubsequence("aaabbaabaaabbabaaabaaab");
document.write(result.from + "→" + result.to);
(The code could be simplified by comparing reverse and value whenever a zero is found, and not just when the end of a maximally long sequence of zeros is encountered.)
You can create an algorithm that only iterates over the input once, and can process an incoming stream of unknown length, by keeping track of two values: the value of the whole string interpreted as a reverse (lsb-to-msb) binary number, and the value of the string with one part reversed. Whenever the reverse value goes below the value of the stored best end-point, a better end-point has been found.
Consider this string as an example:
aaabbaabaaabbabaaabaaab
or, written with zeros and ones for simplicity:
00011001000110100010001
We iterate over the leading zeros until we find the first one:
0001
^
This is the start of the sequence we'll want to reverse. We will start interpreting the stream of zeros and ones as a reversed (lsb-to-msb) binary number and update this number after every step:
reverse = 1, unit = 1
Then at every step, we double the unit and update the reverse number:
0001 reverse = 1
00011 unit = 2; reverse = 1 + 1 * 2 = 3
000110 unit = 4; reverse = 3 + 0 * 4 = 3
0001100 unit = 8; reverse = 3 + 0 * 8 = 3
At this point we find a one, and the sequence of zeros comes to an end. It contains 2 zeros, which is currently the maximum, so we store the current position as a possible end-point, and also store the current reverse value:
endpoint = {position = 6, value = 3}
Then we go on iterating over the string, but at every step, we update the value of the possible endpoint, but now as a normal (msb-to-lsb) binary number:
00011001 unit = 16; reverse = 3 + 1 * 16 = 19
endpoint.value *= 2 + 1 = 7
000110010 unit = 32; reverse = 19 + 0 * 32 = 19
endpoint.value *= 2 + 0 = 14
0001100100 unit = 64; reverse = 19 + 0 * 64 = 19
endpoint.value *= 2 + 0 = 28
00011001000 unit = 128; reverse = 19 + 0 * 128 = 19
endpoint.value *= 2 + 0 = 56
At this point we find that we have a sequence of 3 zeros, which is longer that the current maximum of 2, so we throw away the end-point we had so far and replace it with the current position and reverse value:
endpoint = {position = 10, value = 19}
And then we go on iterating over the string:
000110010001 unit = 256; reverse = 19 + 1 * 256 = 275
endpoint.value *= 2 + 1 = 39
0001100100011 unit = 512; reverse = 275 + 1 * 512 = 778
endpoint.value *= 2 + 1 = 79
00011001000110 unit = 1024; reverse = 778 + 0 * 1024 = 778
endpoint.value *= 2 + 0 = 158
000110010001101 unit = 2048; reverse = 778 + 1 * 2048 = 2826
endpoint.value *= 2 + 1 = 317
0001100100011010 unit = 4096; reverse = 2826 + 0 * 4096 = 2826
endpoint.value *= 2 + 0 = 634
00011001000110100 unit = 8192; reverse = 2826 + 0 * 8192 = 2826
endpoint.value *= 2 + 0 = 1268
000110010001101000 unit = 16384; reverse = 2826 + 0 * 16384 = 2826
endpoint.value *= 2 + 0 = 2536
Here we find that we have another sequence with 3 zeros, so we compare the current reverse value with the end-point's value, and find that the stored endpoint has a lower value:
endpoint.value = 2536 < reverse = 2826
so we keep the end-point set to position 10 and we go on iterating over the string:
0001100100011010001 unit = 32768; reverse = 2826 + 1 * 32768 = 35594
endpoint.value *= 2 + 1 = 5073
00011001000110100010 unit = 65536; reverse = 35594 + 0 * 65536 = 35594
endpoint.value *= 2 + 0 = 10146
000110010001101000100 unit = 131072; reverse = 35594 + 0 * 131072 = 35594
endpoint.value *= 2 + 0 = 20292
0001100100011010001000 unit = 262144; reverse = 35594 + 0 * 262144 = 35594
endpoint.value *= 2 + 0 = 40584
And we find another sequence of 3 zeros, so we compare this position to the stored end-point:
endpoint.value = 40584 > reverse = 35594
and we find it has a smaller value, so we replace the possible end-point with the current position:
endpoint = {position = 21, value = 35594}
And then we iterate over the final digit:
00011001000110100010001 unit = 524288; reverse = 35594 + 1 * 524288 = 559882
endpoint.value *= 2 + 1 = 71189
So at the end we find that position 21 gives us the lowest value, so it is the optimal solution:
00011001000110100010001 -> 00000010001011000100111
^ ^
start = 3 end = 21
Here's a C++ version that uses a vector of bool instead of integers. It can parse strings longer than 64 characters, but the complexity is probably quadratic.
#include <vector>
struct range {unsigned int first; unsigned int last;};
range lexiLeastRev(std::string const &str) {
unsigned int len = str.length(), first = 0, last = 0, run = 0, max_run = 0;
std::vector<bool> forward(0), reverse(0);
bool leading_zeros = true;
for (unsigned int pos = 0; pos < len; pos++) {
bool digit = str[pos] - 'a';
if (!digit) {
if (leading_zeros) continue;
if (++run > max_run || run == max_run && reverse < forward) {
max_run = run;
last = pos;
forward = reverse;
}
}
else {
if (leading_zeros) {
leading_zeros = false;
first = pos;
}
run = 0;
}
forward.push_back(digit);
reverse.insert(reverse.begin(), digit);
}
return range {first, last};
}

The concise 'how many beers' issue?

Where I'm at
I'm trying to figure out how many beers I can buy with 10 RMB after recycling every bottle I get. It's obvious to me that I'm doing something wrong, procedurally, but it's not occurring to me what that is. I'm currently reading "How To Think Like a Computer Scientist: Think Python" on chapter 9. I feel like this should be an easy program for me, but I'm not sure how to loop in the recycling portion of the app. What would be the most concise way to rinse and repeat beer purchases?
The question
Basically, one beer costs 2 RMB. 2 bins gets 1 RMB. 4 caps gets 1 RMB. I'm starting out with 10 RMB. How many beers can I buy (recycling all the bins and caps)?
#5 bottles 5 caps
#= 3 rmb + 1 caps 1 bottles
#6th bottle bought
#= 2rmb + 2 caps
#7th bottle bought
#= 0rmb + 3 caps 1 bottles.
import math
def countbeers(rmb):
beers = 0;
caps = 0;
bins = 0;
bcost = 2;
for i in range (0,rmb):
beers += 1/2
for i in range (0,math.floor(beers)):
caps += 1
bins += 1
rmb = rmb - bcost
for i in range (0,caps):
rmb += 1/4
for i in range (0,bins):
rmb += 1/2
# if rmb > 2 what goes here, trying to loop back through
return beers
print(countbeers(10))
Second attempt
#5 bottles 5 caps
#= 3 wallet + 1 caps 1 bottles
#6th bottle bought
#= 2wallet + 2 caps
#7th bottle bought
#= 0wallet + 3 caps 1 bottles.
import math
global beers
global caps
global bins
global bcost
beers = 0
caps = 0
bins = 0
bcost = 2
def buybeers(wallet):
beers = 0
for i in range (0,wallet):
beers += 1/2
wallet -= 2
return beers
def drinkbeers(beers):
for i in range (0,math.floor(beers)):
caps += 1
bins += 1
wallet = wallet - bcost
return wallet, caps, bins
def recycle(caps, bins):
for i in range (0,caps):
wallet += 1/4
for i in range (0,bins):
wallet += 1/2
return wallet
def maxbeers(wallet):
if wallet > 2:
buybeers(wallet)
if math.floor(beers) > 1:
drinkbeers(beers)
if caps > 4 | bins > 2:
recycle(caps, bins)
return wallet
wallet = int(input("How many wallet do you have?"))
maxbeers(wallet)
if wallet >= 2:
maxbeers(wallet)
elif wallet < 2:
print(beers)
Your main problem is that you are not looping. Every beer you bought from rmb gives you one more bottle, and one more cap. This new bottle and cap might be enough to earn you another rmb, which might be enough for another beer. Your implementation handles this to a limited extent, since you call maxbeers multiple times, but it will not give the correct answer if you give it a truckload of beers, i.e. 25656 bottles.
If you know the number of rmb you have, you can do the calculation by hand on paper and write this:
def maxbeers(rmb):
return 7 # totally correct, I promise. Checked this by hand.
but that's no fun. What if rmb is 25656?
Assuming we can exchange:
2 bottles -> 1 rmb
4 caps -> 1 rmb
2 rmb -> 1 beer + 1 cap + 1 bottle
we calculate it like this, through simulation:
def q(rmb):
beers = 0
caps = 0
bottles = 0
while rmb > 0:
# buy a beer with rmb
rmb -= 2
beers += 1
caps += 1
bottles += 1
# exchange all caps for rmb
while caps >= 4:
rmb += 1
caps -= 4
# exchange all bottles for rmb
while bottles >= 2:
rmb += 1
bottles -= 2
return beers
for a in range(20):
print("rmb:", a, "beers:", q(a))
Then we can buy 20525 beers.

Resources