Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 129 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1760,7 +1760,22 @@ for i in range(7):

## Q. What is a closure in Python?

A closure is said to occur when a nested function references a value in its enclosing scope. The whole point here is that it remembers the value.
In Python, a closure is a function object that has access to variables in its enclosing lexical scope, even when the function is called outside that scope. In other words, a closure allows a function to remember and access the values of the variables in the environment where it was created, even if those variables are no longer in scope when the function is called.

Closures are created when a nested function references a value from its enclosing function. The enclosing function returns the nested function, which maintains a reference to the enclosed value. The enclosed value is stored in the closure, which is attached to the nested function object.

Here's an example of a closure in Python:

```py
def outer_function(x):
def inner_function(y):
return x + y
return inner_function

closure = outer_function(10)
result = closure(5)
print(result) # Output: 15
```

```py
def A(x):
Expand Down Expand Up @@ -2434,7 +2449,17 @@ You can create your own function or use one of Python\'s many built-in functions

## Q. What is recursion?

When a function makes a call to itself, it is termed recursion. But then, in order for it to avoid forming an infinite loop, we must have a base condition. Let\'s take an example.
Recursion is a programming technique in which a function calls itself to solve a problem. The idea is to break down a complex problem into smaller, simpler problems and solve them in a recursive manner until the base case is reached. The base case is a condition that stops the recursion and returns a value.

A common example of a recursive function is the factorial function, which calculates the product of all positive integers up to a given number. Here's an example of a recursive factorial function in Python:

```py
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n-1)
```

```py
def facto(n):
Expand Down Expand Up @@ -4309,15 +4334,113 @@ Using bubble sort.

## Q. How will you check memory leak on Linux?

- valgrind along with gcc.
There are several tools and techniques that can be used to check for memory leaks on Linux:

- Valgrind: Valgrind is a powerful memory debugging tool that can be used to detect memory leaks, among other issues. It works by running the program in a simulated environment that tracks all memory allocations and deallocations, and generates a detailed report of any errors or leaks that it finds.

- LeakSanitizer (LSan): LSan is a lightweight tool that is built into the Clang and GCC compilers. It can be used to detect memory leaks at runtime by instrumenting the code with memory tracking code. When a leak is detected, LSan generates a report that includes the stack trace of the leaking allocation.

- AddressSanitizer (ASan): ASan is another tool built into the Clang and GCC compilers. It can be used to detect a wide range of memory errors, including memory leaks, buffer overflows, and use-after-free errors. Like LSan, ASan instruments the code with memory tracking code and generates a report when an error is detected.

- /proc/meminfo: The /proc/meminfo file contains information about the system's memory usage, including the total amount of memory, the amount of free memory, and the amount of memory used by each process. By monitoring the values in this file over time, it may be possible to detect a memory leak by looking for a steady increase in the amount of memory used by a particular process.

- ps and top: The ps and top commands can be used to monitor the system's memory usage and identify processes that are consuming large amounts of memory. By monitoring the memory usage of a particular process over time, it may be possible to detect a memory leak by looking for a steady increase in the amount of memory used by that process.

In general, detecting and diagnosing memory leaks can be a complex and time-consuming process. It often requires a combination of tools and techniques, as well as a deep understanding of the code and the system's memory usage patterns.

<div align="right">
<b><a href="#">↥ back to top</a></b>
</div>

#### Q. How can you return multiple values from a function?
#### Q. What is the fastest way to swap the values bound to two variables?
#### Q. What is the importance of reference counting?
## Q. How can you return multiple values from a function?

In Python, you can return multiple values from a function by packing them into a tuple or a list. Here's an example using a tuple:

```py
def get_user_info(user_id):
# ... do some work to retrieve user info ...
name = "John Doe"
email = "johndoe@example.com"
age = 35
return name, email, age

# call the function and unpack the returned values
user_name, user_email, user_age = get_user_info(123)

# print the values
print(user_name) # Output: John Doe
print(user_email) # Output: johndoe@example.com
print(user_age) # Output: 35
```

In this example, the `get_user_info` function returns three values (`name`, `email`, and `age`) as a tuple. When the function is called, the returned tuple is unpacked into individual variables (`user_name`, `user_email`, and `user_age`) using tuple unpacking syntax. The variables can then be used as needed.

You can also return multiple values as a list or any other iterable. For example:

```py
def get_user_info(user_id):
# ... do some work to retrieve user info ...
name = "John Doe"
email = "johndoe@example.com"
age = 35
return [name, email, age]

# call the function and unpack the returned values
user_info = get_user_info(123)
user_name, user_email, user_age = user_info

# print the values
print(user_name) # Output: John Doe
print(user_email) # Output: johndoe@example.com
print(user_age) # Output: 35
```

In this example, the get_user_info function returns a list instead of a tuple, and the returned values are unpacked into variables using list unpacking syntax.


## Q. What is the fastest way to swap the values bound to two variables?

In Python, the fastest way to swap the values bound to two variables is to use tuple unpacking, like this:

```py
a, b = b, a
```

In this code, the values of a and b are swapped by creating a tuple of the values in reverse order ((`b`, `a`)) and unpacking them into the variables a and b. The assignment is performed simultaneously, which makes this method faster than using a temporary variable, which requires an additional assignment.

For example:

```py
a = 5
b = 10

# swap the values using tuple unpacking
a, b = b, a

print(a) # Output: 10
print(b) # Output: 5
```

In this example, the values of `a` and `b` are swapped using tuple unpacking, and the final output shows that the values have indeed been swapped.


## Q. What is the importance of reference counting?

In Python, reference counting is a technique used for automatic memory management. It involves keeping track of the number of references to an object and automatically deallocating the object when there are no more references to it.

The importance of reference counting in Python can be summarized as follows:

- Automatic memory management: Reference counting allows Python to automatically manage memory without requiring explicit memory allocation or deallocation by the programmer. This simplifies programming and reduces the risk of memory leaks and other memory-related bugs.

- Efficient memory management: By deallocating objects as soon as they are no longer needed, reference counting helps to minimize the amount of memory used by a program. This is especially important for long-running programs or programs that work with large data sets.

- Improved performance: Because Python uses reference counting to manage memory, it can often achieve better performance than other languages that use garbage collection or other memory management techniques. This is because reference counting can be faster and more predictable than other methods, especially for small or short-lived objects.

- Object lifetime management: Reference counting ensures that objects are deallocated as soon as they are no longer needed, which helps to avoid problems such as dangling pointers or use-after-free errors. This helps to ensure the correctness and reliability of Python programs.

Overall, reference counting is a key feature of Python's automatic memory management system, and it plays an important role in ensuring that Python programs are both efficient and reliable.


#### Q. Do functions return something even if there is not a `return statement?
#### Q. How do you reverse a list?
#### Q. How would you merge two sorted lists?
Expand Down
2 changes: 1 addition & 1 deletion programs/add_to_zero.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ def add_to_zero(nums):
results = doctest.testmod()

if results.failed == 0:
print "ALL TESTS PASSED!"
print("ALL TESTS PASSED!")
2 changes: 1 addition & 1 deletion programs/anagram_of_palindrome.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,4 @@ def is_anagram_of_palindrome(word):
results = doctest.testmod()

if results.failed == 0:
print "ALL TESTS PASSED!"
print("ALL TESTS PASSED!")
2 changes: 1 addition & 1 deletion programs/binary_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,4 @@ def binary_search(val):
results = doctest.testmod()

if results.failed == 0:
print "ALL TESTS PASSED"
print("ALL TESTS PASSED")
2 changes: 1 addition & 1 deletion programs/bst_add_child.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,4 @@ def insert(self, new_data):
results = doctest.testmod()

if results.failed == 0:
print "ALL TESTS PASSED!"
print("ALL TESTS PASSED!")
2 changes: 1 addition & 1 deletion programs/calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def calculate(inner_expression, operators):
nxt = new_expr[op_index+1]
total = int(prev) * int(nxt)
new_expr = new_expr[:op_index-1] + str(total) + new_expr[op_index+2:]
print new_expr
print(new_expr)

while operators['/'] != []:
op_index = operators['/'].pop()
Expand Down
2 changes: 1 addition & 1 deletion programs/coins.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,4 @@ def _coins_2(coins_left, combos, total):
results = doctest.testmod()

if not results.failed:
print 'ALL TESTS PASSED!'
print("ALL TESTS PASSED!")
2 changes: 1 addition & 1 deletion programs/count_employees.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,4 @@ def count_employees(self):
results = doctest.testmod()

if results.failed == 0:
print "ALL TESTS PASSED"
print("ALL TESTS PASSED!")
2 changes: 1 addition & 1 deletion programs/count_recursively.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ def count_recursively(lst):
results = doctest.testmod()

if results.failed == 0:
print "ALL TESTS PASSED!"
print("ALL TESTS PASSED!")
2 changes: 1 addition & 1 deletion programs/create_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,5 @@ def peek(self):
results = doctest.testmod()

if not results.failed:
print "ALL TESTS PASSED!"
print("ALL TESTS PASSED!")

2 changes: 1 addition & 1 deletion programs/create_queue_ll.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,5 +171,5 @@ def print_queue(self):
results = doctest.testmod()

if not results.failed:
print "ALL TESTS PASSED!"
print("ALL TESTS PASSED!")

2 changes: 1 addition & 1 deletion programs/create_stack.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,6 @@ def find_min(self):
print
result = doctest.testmod()
if not result.failed:
print "ALL TESTS PASSED. GOOD WORK!"
print("ALL TESTS PASSED. GOOD WORK!")
print

2 changes: 1 addition & 1 deletion programs/decode_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,4 @@ def _decode_2(s, decoded, i):
results = doctest.testmod()

if results.failed == 0:
print 'ALL TESTS PASSED!'
print("ALL TESTS PASSED!")
2 changes: 1 addition & 1 deletion programs/find_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,4 @@ def find_mode(arr):
results = doctest.testmod()

if not results.failed:
print "ALL TESTS PASSED!"
print("ALL TESTS PASSED!")
2 changes: 1 addition & 1 deletion programs/first_duplicate.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,4 @@ def first_duplicate_optimized(arr):
results = doctest.testmod()

if not results.failed:
print "All tests passed!"
print("All tests passed!")
2 changes: 1 addition & 1 deletion programs/highest_product_of_three.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,4 @@ def highest_product_of_three(list_of_ints):
results = doctest.testmod()

if results.failed == 0:
print "ALL TESTS PASSED!"
print("ALL TESTS PASSED!")
43 changes: 34 additions & 9 deletions programs/is_unique.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
# import unittest


# def is_unique(string):
# """ Takes a string and returns True if it has all unique characters. """

# str_set = set(string)

# return str_set == string


# class Testing(unittest.TestCase):
# def is_unique_test(self):
# assertEqual(is_unique('asdfghjkl'), True)
# assertEqual(is_unique('1234567asdf'), True)
# assertEqual(is_unique('!@#$%^&asdfg123'), True)
# assertEqual(is_unique('abcdABCD'), True)

# assertEqual(is_unique('asdfghjkll'), False)
# assertEqual(is_unique('1qwerty1'), False)
# assertEqual(is_unique('poiu$asdf$'), False)

# if __name__ == '__main__':
# unittest.main()

import unittest


Expand All @@ -10,15 +35,15 @@ def is_unique(string):


class Testing(unittest.TestCase):
def is_unique_test(self):
assertEqual(is_unique('asdfghjkl'), True)
assertEqual(is_unique('1234567asdf'), True)
assertEqual(is_unique('!@#$%^&asdfg123'), True)
assertEqual(is_unique('abcdABCD'), True)

assertEqual(is_unique('asdfghjkll'), False)
assertEqual(is_unique('1qwerty1'), False)
assertEqual(is_unique('poiu$asdf$'), False)
def test_is_unique(self):
self.assertEqual(is_unique('asdfghjkl'), True)
self.assertEqual(is_unique('1234567asdf'), True)
self.assertEqual(is_unique('!@#$%^&asdfg123'), True)
self.assertEqual(is_unique('abcdABCD'), True)

self.assertEqual(is_unique('asdfghjkll'), False)
self.assertEqual(is_unique('1qwerty1'), False)
self.assertEqual(is_unique('poiu$asdf$'), False)

if __name__ == '__main__':
unittest.main()
23 changes: 23 additions & 0 deletions programs/rommon_to_integer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
def roman_to_int(s: str) -> int:
roman_dict = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}
result = 0
for i in range(len(s)):
if i < len(s) - 1 and roman_dict[s[i]] < roman_dict[s[i+1]]:
result -= roman_dict[s[i]]
else:
result += roman_dict[s[i]]
return result


'''
>>> roman_to_int('III')
3
>>> roman_to_int('IV')
4
>>> roman_to_int('IX')
9
>>> roman_to_int('LVIII')
58
>>> roman_to_int('MCMXCIV')
1994
'''