Home
Get Hired
40+ Uber Interview Questions (2024) For Engineers With Detailed Answers
40+ Uber Interview Questions (2024) For Engineers With Detailed Answers
Uber Technologies Inc. is a tech mobility company established in March 2009, with its headquarters in San Francisco, California, USA. The Uber interview questions are curated to help applicants ace their interviews with Uber.
Shivani Goyal
0 min read
0 min read
Table of content:
Uber Interview Questions For Engineering Profiles: Coding
Technical Uber Interview Questions: Theoretical
Uber Interview Question: HR Round
Uber Recruitment Procedure
About Uber Technologies Ltd.
Uber is one of the best car-booking apps with a global presence. But while all of us must have used this app for its cab/ delivery services, not everyone is consciously aware that Uber is a technology company that uses tech solutions to provide mobility as a service. The company is present in about 10,500 cities across 70 countries with 131M active users. Working on and contributing to the tech solutions for the company is a golden opportunity and a dream come true for many. In this article, we will discuss some top Uber interview questions with answers that you must know if you want to ace that interview. In addition, we will also look at the recruitment process to help facilitate your prep. So let's get started!
Uber Interview Questions For Engineering Profiles: Coding
Q1. You are given a string s containing lowercase alphabets. Write a function that finds the length of the longest substring with unique characters in s.
Note:
The length of the longest unique substring is obtained by finding a substring that does not contain any repeated characters and has the maximum length.
Constraints:
The input string s can have up to 10^5 characters.
The string s only contains lowercase alphabets.
Ans. The solution to this problem is given in the code snippet below:
#include
#include
#include
int longestUniqueSubstring(const std::string& s) {
int n = s.length();
int maxLength = 0;
int i = 0, j = 0;
std::unordered_set uniqueChars;
while (j < n) {
if (uniqueChars.find(s[j]) == uniqueChars.end()) {
uniqueChars.insert(s[j]);
maxLength = std::max(maxLength, j - i + 1);
j++;
} else {
uniqueChars.erase(s[i]);
i++;
}
}
return maxLength;
}
The solution uses a sliding window approach to find the length of the longest substring with unique characters in the given strings. It initializes variables i and j to track the start and end indices of the current substring.
The algorithm uses an unordered set uniqueChars to keep track of the characters in the current substring. It starts with an empty set.
The algorithm iterates through the string from left to right using the indices i and j. For each character at index j, it checks if the character is already in the uniqueChars set. If the character is not found (indicating uniqueness), it adds the character to the set, updates the maxLength if necessary, and moves the end index j one step forward.
If the character is already in the set (indicating repetition), it removes the character at index i from the set, moves the start index i one step forward, and continues the iteration.
By maintaining the sliding window and updating the maxLength whenever a unique substring is found, the algorithm ensures that the final maxLength represents the length of the longest substring with unique characters in the string s.
Finally, the function returns the calculated maxLength.
Q2.You are tasked with implementing a queue data structure. The queue should support two operations: enqueue and dequeue. The enqueue operation adds an element to the end of the queue, and the dequeue operation removes and returns the element at the front of the queue.
Note:
The Queue the class should correctly implement the enqueue and dequeue operations, ensuring that elements are added to the end of the queue and removed from the front of the queue.
Constraints:
The enqueue operation can be called multiple times.
The dequeue operation can only be called after at least one element has been enqueued.
All elements are positive integers.
Solution:
#include
#include
class Queue {
private:
std::queue queue;
public:
void enqueue(int item) {
queue.push(item);
}
int dequeue() {
if (!is_empty()) {
int front = queue.front();
queue.pop();
return front;
} else {
throw std::runtime_error("Cannot dequeue from an empty queue.");
}
}
bool is_empty() {
return queue.empty();
}
int size() {
return queue.size();
}
};
int main() {
// Create a new queue
Queue queue;
// Enqueue elements
queue.enqueue(10);
queue.enqueue(20);
queue.enqueue(30);
// Dequeue elements
std::cout << queue.dequeue() << std::endl; // Output: 10
std::cout << queue.dequeue() << std::endl; // Output: 20
// Check if the queue is empty
std::cout << std::boolalpha << queue.is_empty() << std::endl; // Output: false
// Get the current size of the queue
std::cout << queue.size() << std::endl; // Output: 1
return 0;
}
Q3. You are given a binary tree represented as a linked structure. Each node in the tree has an integer value. Write a function that returns the sum of all the values in the tree.
Note: The sum of all the values in the binary tree is obtained by traversing the tree and accumulating the values.
Constraints:
The binary tree can have up to 10^5 nodes.
Each node value is an integer between -10^4 and 10^4.
Ans.
int sumBinaryTree(TreeNode* root) {
if (root == nullptr) {
return 0;
}
int leftSum = sumBinaryTree(root->left);
int rightSum = sumBinaryTree(root->right);
return root->val + leftSum + rightSum;
}
The solution uses a recursive approach to calculate the sum of all the values in the binary tree. The sumBinaryTree function takes a TreeNode* parameter representing the root of the binary tree.
In the function, it first checks if the current node is nullptr. If it is, it returns 0, as there are no values to add.
If the current node is not nullptr, it recursively calculates the sum of the values in the left subtree by calling sumBinaryTree on the left child node. Similarly, it calculates the sum of the values in the right subtree by calling sumBinaryTree on the right child node.
Finally, it returns the sum of the current node's value, the sum of the values in the left subtree, and the sum of the values in the right subtree.
The recursion continues until all nodes have been visited, and the sum of all the values in the binary tree is obtained.
Q4: Check if a given linked list contains a cycle. How do you find the starting node of the cycle?
Ans. To check if a given linked list contains a cycle, we can use Floyd's cycle-finding algorithm, also known as the "tortoise and hare" algorithm. This algorithm uses two pointers, a slow pointer, and a fast pointer, to traverse the linked list.
Here is the approach to detecting a cycle in a linked list:
Initialize two pointers, slow and fast, pointing to the head of the linked list.
Move the slow pointer one step at a time and the fast pointer two steps at a time.
If the fast pointer encounters a null node, it means there is no cycle in the linked list, so we can return false.
If the fast pointer and the slow pointer meet at some point, it indicates the presence of a cycle in the linked list.
To find the starting node of the cycle, reset the slow pointer to the head of the linked list and keep the fast pointer at the meeting point.
Move both pointers one step at a time until they meet again. The node at which they meet will be the starting node of the cycle.
The hasCycle function checks whether a given linked list contains a cycle using Floyd's cycle-finding algorithm. It returns true if a cycle is found and false otherwise.
The findCycleStart function finds the starting node of the cycle in a linked list. It first uses Floyd's algorithm to determine if a cycle exists. If a cycle is found, it resets the slow pointer to the head and moves both pointers one step at a time until they meet again at the starting node of the cycle. Finally, it returns the starting node or nullptr if no cycle is present.
You can use these functions to check for a cycle in a linked list and find the starting node if a cycle exists.
Q5. You are given a binary integer represented as a string. Your task is to implement a function that converts the binary integer to its decimal representation.
Note: The solution should convert the binary integer to its decimal representation using the base-2 to base-10 conversion. The binary integer can have leading zeros and can be of any length.
Constraints:
The binary integer represented as a string will contain only '0' and '1' characters.
The length of the binary integer will not exceed 10^5.
Ans. To convert a binary integer to its decimal representation, we can iterate over the binary string from left to right and calculate the decimal value using the base-2 to base-10 conversion.
Here's the C++ implementation of the binaryToDecimal function:
#include
int binaryToDecimal(const std::string& binary) {
int decimal = 0;
int power = 1;
for (int i = binary.length() - 1; i >= 0; i--) {
if (binary[i] == '1') {
decimal += power;
}
power *= 2;
}
return decimal;
}
The binaryToDecimal function takes a string binary as input, representing the binary integer, and returns the decimal representation as an integer.
The function initializes two variables, decimal and power. decimal keeps track of the calculated decimal value and power represents the power of 2 in the base-2 to base-10 conversion.
We iterate over the binary string from right to left using the variable i, starting from the last character (binary.length() - 1) and decrementing i until it reaches 0. Within each iteration, we check if the current character is '1'. If it is, we add the corresponding decimal value to decimal by adding power. After that, we update power by multiplying it by 2 to consider the next bit position.
Finally, we return the calculated decimal value, which represents the decimal representation of the given binary integer.
This approach converts the binary integer to its decimal representation by traversing the binary string and accumulating the decimal value based on the base-2 to base-10 conversion.
Q6.You are given an array of integers, nums, of length n. Your task is to find the maximum sum of any contiguous subarray within nums.
Note: The maximum subarray sum is obtained by selecting a contiguous subarray with the largest sum.
Constraints:
1 <= n <= 10^5
-10^4 <= nums[i] <= 10^4
Ans.Arrays are a very common topic that all engineering candidates must be aware of when appearing for an Uber interview. The solution for this question is-
#include
#include
int maxSubarraySum(std::vector& nums, int n) {
int maxSum = nums[0];
int currentSum = nums[0];
for (int i = 1; i < n; ++i) {
currentSum = std::max(nums[i], currentSum + nums[i]);
maxSum = std::max(maxSum, currentSum);
}
return maxSum;
}
The solution uses Kadane's algorithm to find the maximum sum of any contiguous subarray within the given array nums. It initializes two variables: maxSum and currentSum. The maxSum variable keeps track of the maximum sum found so far, and the currentSum variable stores the sum of the current subarray being considered.
The algorithm iterates through the array starting from the second element. For each element, it calculates the maximum between the current element itself and the sum of the current element and the previous subarray sum (currentSum + nums[i]). This step determines whether it is better to start a new subarray from the current element or to continue the existing subarray. The currentSum is updated accordingly.
After updating the currentSum, the algorithm compares it with the current maximum sum (maxSum). If the currentSum is greater, it becomes the new maxSum.
Finally, when the iteration is completed, the function returns the maximum sum found, which represents the maximum sum of any contiguous subarray within nums.
Q7. You are given a 2D array of integers with dimensions m x n. Implement a function that finds the maximum value in the array and its corresponding row and column indices.
Constraints:
The 2D array matrix will have at least one element.
The dimensions of the matrix, m and n, will not exceed 100.
Ans. To find the maximum value in a 2D array along with its corresponding row and column indices, we can iterate over the entire array and keep track of the maximum value and its indices.
Here's the C++ implementation of the findMaxValue function:
#include
#include
std::pair<int, std::pair<int, int>> findMaxValue(const std::vector<std::vector>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
int maxVal = matrix[0][0];
int rowIndex = 0;
int colIndex = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] > maxVal) {
maxVal = matrix[i][j];
rowIndex = i;
colIndex = j;
}
}
}
return std::make_pair(maxVal, std::make_pair(rowIndex, colIndex));
}
Q8. You are given an array of non-negative integers of size n. Your task is to implement a function to find the maximum possible sum of a subarray with the constraint that no two elements in the subarray are adjacent.
Note: The solution should find the maximum sum of a subarray with the constraint that no two elements in the subarray are adjacent. The subarray can be of any length, including 0.
Constraints:
The array nums can contain up to 10^5 non-negative integers.
Each element in nums is a non-negative integer not exceeding 10^4.
Ans. To find the maximum possible sum of a subarray with the constraint that no two elements in the subarray are adjacent, we can use dynamic programming to build a table of subproblem solutions.
Here's the C++ implementation of the maximumNonAdjacentSum function:
#include
#include
int maximumNonAdjacentSum(const std::vector& nums) {
int n = nums.size();
if (n == 0) {
return 0;
}
int incl = nums[0];
int excl = 0;
for (int i = 1; i < n; i++) {
int temp = std::max(incl, excl);
incl = excl + nums[i];
excl = temp;
}
return std::max(incl, excl);
}
The maximumNonAdjacentSum function takes a vector of non-negative integers nums as input and returns the maximum possible sum of a subarray with the constraint that no two elements in the subarray are adjacent. The function first checks if the input vector is empty. If it is, it returns 0 since there are no elements to consider. Then, it initializes two variables, incl and excl, to keep track of the maximum sum, including the current element and excluding the current element, respectively. We start by considering the first element of the vector. Next, we iterate over the remaining elements of the vector, updating the incl and excl values accordingly. At each step, we compare the maximum sum obtained by including the current element (current element + previous excl) with the maximum sum obtained by excluding the current element (previous incl or excl). We update incl and excl accordingly. Finally, we return the maximum value between incl and excl, which represents the maximum possible sum of a subarray with the given constraint. The dynamic programming approach allows us to efficiently compute the maximum sum by considering the adjacent element constraint and avoiding redundant calculations.
Q9. You are given a grid of size m x n, where each cell represents a possible position. You can only move either down or right at any point in time. The goal is to find the number of unique pathways from the top-left cell to the bottom-right cell of the grid.
Note: The solution should count the number of unique pathways by considering only the allowed movements (down and right) and finding all possible paths from the starting cell to the destination cell.
Constraints:
The grid dimensions m and n are positive integers.
The grid can have a maximum size of 100 x 100.
Ans. To find the number of unique pathways from the top-left cell to the bottom-right cell in a grid, we can use dynamic programming to build a table of subproblem solutions.
Here's the C++ implementation of the uniquePaths function:
#include
int uniquePaths(int m, int n) {
std::vector<std::vector> dp(m, std::vector(n, 0));
// Base case: There is only one way to reach any cell in the first row or first column
for (int i = 0; i < m; i++) {
dp[i][0] = 1;
}
for (int j = 0; j < n; j++) {
dp[0][j] = 1;
}
// Fill the table by summing the number of ways from the above cell and left cell
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
// Return the number of unique pathways to reach the bottom-right cell
return dp[m-1][n-1];
}
Q10.You are given a string representing a file directory path. Your task is to simplify the directory path by removing unnecessary "." and ".." symbols.
Constraints:
The directory path can have up to 10^5 characters.
The characters in the path are alphanumeric and can include the following special characters: "", ".", "..".
Ans. To simplify a directory path, we can use a stack data structure to keep track of the valid directory names while iterating through the path. We push valid directory names onto the stack and handle special cases for "." and ".." symbols.
Here's the C++ implementation of the simplifyDirectoryPath function:
#include
#include
#include
std::string simplifyDirectoryPath(const std::string& path) {
std::stack directoryStack;
// Split the path by '/'
std::stringstream ss(path);
std::string directory;
while (getline(ss, directory, '/')) {
if (directory.empty() || directory == ".") {
continue; // Ignore empty or current directory "."
} else if (directory == "..") {
if (!directoryStack.empty()) {
directoryStack.pop(); // Go back to the parent directory ".."
}
} else {
directoryStack.push(directory); // Push valid directory names onto the stack
}
}
// Construct the simplified path
std::string simplifiedPath;
while (!directoryStack.empty()) {
simplifiedPath = "" + directoryStack.top() + simplifiedPath;
directoryStack.pop();
}
return simplifiedPath
The simplifyDirectoryPath function takes a string path as input and returns the simplified directory path as a string.
The function first initializes an empty stack directoryStack to store the valid directory names. It then splits the input path using a stringstream and iterates over the resulting directories.
Within the iteration, it checks for special cases. If the directory is empty or ".", it is ignored. If the directory is ".." and the stack is not empty, it means we need to go back to the parent directory, so the top directory is popped from the stack.
For any other valid directory name, it is pushed onto the stack.
Once the iteration is complete, the function constructs the simplified path by popping the directory names from the stack and concatenating them with a "" separator. Finally, it returns the simplified path or "" if the path is empty.
Q11.You are given an undirected tree represented as an array tree of length n, where tree[i] represents the parent node of node i in the tree. The root of the tree is denoted by tree[0], and its value is set to -1.
Write a function that determines whether the given tree is a valid tree or not. Explanation:
The array tree represents the following tree structure:
0 / \ 1 2 / \ 3 4
The tree is a valid tree because it satisfies the following conditions:
There are no cycles or loops in the tree.
All nodes except the root have exactly one parent.
The tree is connected, meaning that there is a path between any two nodes in the tree.
Note: The tree is a valid tree because it satisfies all the conditions mentioned.
Constraints:
1 <= n <= 10^4
-1 <= tree[i] < n
Ans.
def isValidTree(tree): n = len(tree) parent_count = [0] * n
for i in range(n): parent = tree[i] if parent != -1: parent_count[parent] += 1
root_count = 0 for count in parent_count: if count > 1: return False if count == 0: root_count += 1 if root_count > 1: return False
return True
The solution checks whether the given array tree represents a valid tree by following these steps:
It initializes a list parent_count to keep track of the number of children each node has.
It iterates through the array tree and increments the count for each parent encountered.
After counting the parents, it checks if there is more than one child for any node (excluding the root). If so, it returns False, as a tree cannot have multiple children for a single parent.
It also checks if there is more than one root in the tree. If there is, it returns False, as a tree should have only one root.
If no invalid conditions are found, it returns True, indicating that the given tree is valid.
Q12. You are given an array of integers, nums, of length n. Your task is to write a function that returns an array result of length n, where result[i] is the next greater element for nums[i]. If there is no next greater element for nums[i], the corresponding value in result[i] should be -1.
Note: For each element in the nums array, there is no element greater than the current element. Hence, the output array next_greater contains -1 for each element.
Constraints:
1 <= n <= 10^4
-10^9 <= nums[i] <= 10^9
Ans.
def nextGreaterElement(nums): n = len(nums) stack = [] result = [-1] * n
for i in range(n): while stack and nums[i] > nums[stack[-1]]: index = stack.pop() result[index] = nums[i] stack.append(i)
return result
The solution uses a stack to keep track of the indices of elements that do not have a next greater element yet. It iterates through the array and compares each element with the top of the stack. If the current element is greater than the element at the top of the stack, it means the current element is the next greater element for the element at the top of the stack. The process continues until the stack is empty or the current element is not greater than the element at the top of the stack. Finally, the function returns the resulting array result.
Q13. Write a program to reverse a given string or an array
Ans. Reversal of arrays is one of the basic topics that often features in technical interview rounds for most companies. A sample solution for the above-mentioned Uber interview question is given below-
#include <bits/stdc++.h>
using namespace std;
/* Function to reverse arr[] from start to end*/
void rvereseArray(int arr[], int start, int end)
{
while (start < end)
{
int temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
start++;
end--;
}
}
/* Utility function to print an array */
void printArray(int arr[], int size)
{
for (int i = 0; i < size; i++)
cout << arr[i] << " ";
cout << endl;
}
/* Driver function to test above functions */
int main()
{
int arr[] = {1, 2, 3, 4, 5, 6};
int n = sizeof(arr) / sizeof(arr[0]);
// To print original array
printArray(arr, n);
// Function calling
rvereseArray(arr, 0, n-1);
cout << "Reversed array is" << endl;
// To print the Reversed array
printArray(arr, n);
return 0;
}
Q14. Write a program to show multiple inheritances.
Ans. Inheritance is an important part of object-oriented programming that you must be familiar with. Here is the program to show multiple inheritances-
#include
using namespace std;
class A
{
public:
A() { cout << "A's constructor called" << endl; }
};
class B
{
public:
B() { cout << "B's constructor called" << endl; }
};
class C: public B, public A // Note the order
{
public:
C() { cout << "C's constructor called" << endl; }
};
int main()
{
C c;
return 0;
}
Q15. Write a program to find the largest element in an array.
This is a basic question about the array that you might come across in your Uber interview. The code solution given below showcases how to find the largest element in an array.
#include <bits/stdc++.h>
using namespace std;
int largest(int arr[], int n)
{
int i;
// Initialize maximum element
int max = arr[0];
// Traverse array elements
// from second and compare
// every element with current max
for (i = 1; i < n; i++)
if (arr[i] > max)
max = arr[i];
return max;
}
// Driver Code
int main()
{
int arr[] = {10, 324, 45, 90, 9808};
int n = sizeof(arr) / sizeof(arr[0]);
cout << "Largest in given array is "
<< largest(arr, n);
return 0;
}
Q16. Write a recursive program for searching an element linearly in an array.
Ans. In the code snippet below, you will find the recursive program needed-
#include
using namespace std;
// Recursive function to search for x in arr[]
int searchElement(int arr[], int size, int x) {
size--;
// Base case (Element not present in the array)
if (size < 0) {
return -1;
}
// Base case (Element found, return its position)
if (arr[size] == x) {
return size;
}
// Recursive case
return searchElement(arr, size, x);
}
// Driver code
int main() {
int arr[] = {17, 15, 11, 8, 13, 19};
int size = sizeof(arr) / sizeof(arr[0]);
int x = 11;
int idx = searchElement(arr, size, x);
if (idx != -1)
cout << "Element " << x << " is present at index " <<idx;
else
cout << "Element " << x << " is not present in the array";
return 0;
}
Q17. Write a program to find the number which is occurring an odd number of times.
This is an interesting question, and anyone hoping to crack an Uber interview must be able to write a functional code for the same. An example is given below:
int getOddOccurrence(int arr[], int arr_size)
{
for (int i = 0; i < arr_size; i++) {
int count = 0;
for (int j = 0; j < arr_size; j++)
{
if (arr[i] == arr[j])
count++;
}
if (count % 2 != 0)
return arr[i];
}
return -1;
}
// driver code
int main()
{
int arr[] = { 2, 3, 5, 4, 5, 2,
4, 3, 5, 2, 4, 4, 2 };
int n = sizeof(arr) / sizeof(arr[0]);
// Function calling
cout << getOddOccurrence(arr, n);
return 0;
}
Q18. Write a program to search an element in a rotated and sorted array.
Ans. The functional code given below provides the solution to the above question-
#include <bits/stdc++.h>
using namespace std;
// Standard Binary Search function
int binarySearch(int arr[], int low, int high, int key)
{
if (high < low)
return -1;
int mid = (low + high) / 2;
if (key == arr[mid])
return mid;
if (key > arr[mid])
return binarySearch(arr, (mid + 1), high, key);
return binarySearch(arr, low, (mid - 1), key);
}
// Function to get pivot. For array 3, 4, 5, 6, 1, 2
// it returns 3 (index of 6)
int findPivot(int arr[], int low, int high)
{
// Base cases
if (high < low)
return -1;
if (high == low)
return low;
// low + (high - low)/2;
int mid = (low + high) / 2;
if (mid < high && arr[mid] > arr[mid + 1])
return mid;
if (mid > low && arr[mid] < arr[mid - 1])
return (mid - 1);
if (arr[low] >= arr[mid])
return findPivot(arr, low, mid - 1);
return findPivot(arr, mid + 1, high);
}
// Searches an element key in a pivoted
// sorted array arr[] of size n
int pivotedBinarySearch(int arr[], int n, int key)
{
int pivot = findPivot(arr, 0, n - 1);
// If we didn't find a pivot,
// then array is not rotated at all
if (pivot == -1)
return binarySearch(arr, 0, n - 1, key);
// If we found a pivot, then first compare with pivot
// and then search in two subarrays around pivot
if (arr[pivot] == key)
return pivot;
if (arr[0] <= key)
return binarySearch(arr, 0, pivot - 1, key);
return binarySearch(arr, pivot + 1, n - 1, key);
}
// Driver program to check above functions
int main()
{
// Let us search 3 in below array
int arr1[] = { 5, 6, 7, 8, 9, 10, 1, 2, 3 };
int n = sizeof(arr1) / sizeof(arr1[0]);
int key = 3;
// Function calling
cout << "Index of the element is : "
<< pivotedBinarySearch(arr1, n, key);
return 0;
}
Q19. Write a program to rotate an array.
Ans. Below is a popular answer to this question-
#include <bits/stdc++.h>
using namespace std;
// Fuction to rotate array
void Rotate(int arr[], int d, int n)
{
// Storing rotated version of array
int temp[n];
// Keepig track of the current index
// of temp[]
int k = 0;
// Storing the n - d elements of
// array arr[] to the front of temp[]
for (int i = d; i < n; i++) {
temp[k] = arr[i];
k++;
}
// Storing the first d elements of array arr[]
// into temp
for (int i = 0; i < d; i++) {
temp[k] = arr[i];
k++;
}
// Copying the elements of temp[] in arr[]
// to get the final rotated array
for (int i = 0; i < n; i++) {
arr[i] = temp[i];
}
}
// Function to print elements of array
void PrintTheArray(int arr[], int n)
{
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
}
// Driver code
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7 };
int N = sizeof(arr) / sizeof(arr[0]);
int d = 2;
// Function calling
Rotate(arr, d, N);
PrintTheArray(arr, N);
return 0;
}
Q20. Find the sum of elements in a given array.
Even if you are a fresher, you must know how to give a sample code to answer this interview question. Check the code snippet below to know how-
/* C++ Program to find sum of elements
in a given array */
#include <bits/stdc++.h>
using namespace std;
// function to return sum of elements
// in an array of size n
int sum(int arr[], int n)
{
int sum = 0; // initialize sum
// Iterate through all elements
// and add them to sum
for (int i = 0; i < n; i++)
sum += arr[i];
return sum;
}
// Driver code
int main()
{
int arr[] = {12, 3, 4, 15};
int n = sizeof(arr) / sizeof(arr[0]);
cout << "Sum of given array is " << sum(arr, n);
return 0;
}
Q21. Write a program to show how a derived class gets more restrictive access.
Ans. The code program is-
#include
using namespace std;
class Base {
public:
virtual int fun(int i) { cout << "Base::fun(int i) called"; }
};
class Derived: public Base {
private:
int fun(int x) { cout << "Derived::fun(int x) called"; }
};
int main()
{
Base *ptr = new Derived;
ptr->fun(10);
return 0;
}
Technical Uber Interview Questions: Theoretical
In this section, we will have a look at some important questions you might come across in an interview at Uber. You will find many important computer science and programming concepts covered in these questions, with answers more on the theoretical side.
Q22. What do you mean by a Distributed Database Management System with Transparency?
A distributed database management system (DDBMS) is a type of database management system that manages a database that is spread across multiple computers or nodes in a network. In a DDBMS, data is stored in multiple nodes and accessed through a network.
Now, a distributed database management system (DDBMS) with transparency is a type of database management system that enables data to be distributed across multiple computer systems or nodes while providing transparency to the users and applications that access the database. Transparency in this context refers to the ability of the DDBMS to hide the underlying complexities of the distributed system from the end-users and applications. Note that the physical structure (or physical storage structure) is the memory manager of a database management system. It describes how data is saved on a disc.
A distributed database management system with transparency provides several benefits, including improved performance, scalability, availability, and fault tolerance. By distributing data across multiple nodes, a DDBMS can improve the performance of database operations by enabling parallel processing and reducing network traffic. Additionally, a DDBMS can improve the availability and fault tolerance of the database by replicating data across multiple nodes, which can ensure that the database remains operational even if some of the nodes fail.
Transparency is achieved in a DDBMS through several mechanisms, including the following-
Location transparency: This ensures that end-users and applications can access the data without knowing the physical location of the data in the network. That is, it hides the physical location of the database from users and applications.
Replication transparency: Users and applications should be able to access the data without knowing whether the data is replicated across multiple nodes or not.
Fragmentation transparency: Users and applications should be able to access the data without knowing how the data is partitioned or distributed across the nodes.
Concurrency transparency: Users and applications should be able to access the data without being aware of the concurrency control mechanisms used to ensure data consistency.
Naming transparency: It ensures that the names of data items are consistent across the distributed system, even if they are physically stored on different nodes.
Transaction transparency: It ensures that transactions can be executed across multiple nodes in a distributed system while appearing to the end-users and applications as a single atomic transaction.
Overall, a distributed database management system with transparency provides users and applications with a unified view of the database, even though the database is distributed across multiple nodes. It also provides benefits to organizations that require large-scale, distributed databases with high performance, availability, and fault tolerance. This makes it easier for developers to build applications that can work with large amounts of data and allows for better performance and availability compared to a centralized database.
Q23. Explain the meaning of a Bootstrap Program in reference to operating systems.
A bootstrap program, also known as a boot loader or bootstrap loader, is a program that is responsible for starting an operating system (OS) when a computer or device is powered on or reset. The bootstrap program is typically stored in non-volatile memory, such as read-only memory (ROM) or flash memory, and is executed by the computer's central processing unit (CPU) at startup.
The Bootstrap program performs several functions, including:
Power-on self-test (POST): The bootstrap program performs a diagnostic test of the computer's hardware components, such as the CPU, memory, and input/output devices, to ensure that they are functioning properly.
Bootstrapping the OS: Once the POST is completed, the bootstrap program loads the operating system from the storage device, such as a hard disk, into the computer's memory. It then transfers control to the operating system, which takes over the management of the computer.
Initializing system resources: The bootstrap program initializes system resources, such as device drivers, that the operating system will use to communicate with hardware devices.
Providing a user interface: Some bootstrap programs provide a basic user interface that allows the user to select which operating system or application to start.
Overall, the bootstrap program is an essential component of the startup process for a computer or device and plays a critical role in getting the system up and running.
Q24: What is demand paging in operating systems?
Demand paging is a memory management technique used in operating systems to efficiently manage system memory. In a demand-paged system, programs are not loaded entirely into memory when they are launched. Instead, only the parts of the program that are needed are loaded into memory on demand as they are requested by the program.
Demand paging is based on the principle of locality of reference, which states that programs tend to access a small portion of their code and data frequently and other parts infrequently or not at all. The demand paging system takes advantage of this principle by loading only the pages that are needed and paging out those that are not needed.
When a program makes a reference to a memory page that is not currently in physical memory, a page fault occurs. The operating system then retrieves the missing page from the disk, stores it in memory, and updates the page table to reflect the new location of the page. The program can then continue executing as if the page had been in memory all along.
Demand paging has several benefits, including:
It allows programs to be larger than the amount of physical memory available, as only the parts of the program that are needed are loaded into memory.
It reduces the amount of time it takes to launch programs, as only the necessary pages are loaded into memory.
It increases system responsiveness, as memory can be allocated on-demand as needed, rather than having to allocate all memory at startup.
It reduces overall memory usage, as memory is only allocated for the parts of the program that are actually used.
Overall, demand paging is a powerful technique for managing system memory and is widely used in modern operating systems.
Q25. What is a VPN (Virtual Private Network)? How many types of VPNs are there?
A Virtual Private Network (VPN) is a secure network connection that allows users to access and transmit data over the internet as if they were connected to a private network. A VPN encrypts the user's internet traffic and routes it through a remote server or a network of servers, masking their IP address and providing them with a secure and private internet connection.
There are several types of VPNs, including:
Remote Access VPN: This type of VPN allows individual users to connect to a private network remotely over the internet. Remote access VPNs are commonly used by remote workers, telecommuters, and business travelers to securely access their company's network resources.
Site-to-Site VPN: This type of VPN is used to connect two or more networks together over the internet. Site-to-site VPNs are commonly used by businesses to connect their branch offices or data centers together securely.
Client-to-Site VPN: This type of VPN is similar to remote access VPN, but instead of connecting individual users, it allows an entire client public network to connect to a private network over the internet.
MPLS VPN: This type of VPN uses Multiprotocol Label Switching (MPLS) technology to create a private network connection over the internet. MPLS VPNs are commonly used by businesses to connect their branch offices together securely.
SSL VPN: This type of VPN uses Secure Socket Layer (SSL) technology to create a secure connection between a user's web browser and a remote server. SSL VPNs are commonly used to provide remote access to web-based applications.
Overall, VPNs provide a secure and private network connection over the internet, and there are several types of VPNs that are used for different purposes.
Q26. Explain the concept of microkernels in reference to OS.
In the context of operating systems, a microkernel is a minimalistic kernel architecture that provides only the essential kernel services required for the management of hardware resources and the execution of basic system functions. The microkernel approach to OS design involves separating the kernel into small, modular components, each of which runs in user space and communicates with other components via message passing.
Microkernels are designed to be small, simple, and modular, with a minimal set of kernel services running in the kernel space. A microkernel typically consists of a small set of basic services, such as thread management, interprocess communication (IPC), and memory management.
This approach helps in delegating operating system functionality to user address space processes, and microkernels can also provide more fine-grained control over system resources, which can improve system performance and scalability. In simpler terms, it allows for greater flexibility and customization, as additional services can be added or removed without affecting the kernel's core functionality. By running most of the OS functions in user space, microkernels are also more resilient to failures, as a failure in one component does not affect the entire system.
The microkernel architecture is in contrast to the monolithic kernel architecture, which is a more traditional approach to OS design that combines all OS functions into a single large kernel. Monolithic kernels tend to be less modular and less flexible than microkernels, but they can be more efficient in terms of performance because of the reduced overhead associated with message passing in a microkernel-based system.
In a nutshell, microkernels are a powerful approach to OS design that allows for greater flexibility, customization, and resilience. They are commonly used in embedded systems, real-time systems, and other specialized applications where reliability and security are of utmost importance. One of the most well-known microkernel-based operating systems is GNU Hurd, which is a collection of servers running on top of the Mach microkernel. Other examples of microkernel-based operating systems include QNX, L4, and MINIX.
Q27. What is the difference between Swapping and Paging?
Swapping and paging are two memory management techniques used in operating systems, and while they both involve moving data between main memory and secondary storage, they differ in how they do so.
SWAPPING
PAGING
Swapping involves moving entire processes between main memory and secondary memory/ storage.
Paging, on the other hand, involves breaking up a process into smaller fixed-sized units called pages, which can be loaded into and out of main memory as needed.
When a process is swapped out of main memory, its entire contents are written to disk or to secondary memory. This frees up memory for other processes.
When a process references a memory location (memory reference) that is not currently in main memory, a page fault occurs, and the required page is loaded into memory from the disk.
Swapping is generally used when the amount of memory required by a process exceeds the amount of available physical memory.
Paging allows for more efficient use of available memory by only loading the pages of a process that are actually needed rather than swapping the entire process in and out of memory.
The temporary transfer of a process from the main memory to the secondary memory takes place.
In Paging, a contiguous block of memory is made non-contiguous but of a fixed size called a frame or pages.
No memory management is required.
Non-contiguous Memory Management is required.
Solution direction is provided
No efficient solution direction is provided
In summary, the main difference between swapping and paging is that swapping moves entire processes in and out of memory, while paging moves smaller units of memory (pages) in and out of memory. Swapping is typically used when large amounts of memory are required, while paging is used for more efficient memory utilization.
Q28. What is Servlet Collaboration?
Servlet Collaboration is a mechanism in Java Servlet technology that allows multiple servlets to work together to generate a response for a client request. Servlet Collaboration is typically used when a single servlet is not capable of handling a client request on its own, or when multiple servlets need to work together to generate a response that is too complex for a single servlet to handle.
In Servlet Collaboration, one servlet typically initiates the request and passes control to another servlet by forwarding the request to it. The second servlet then processes the request and generates a response, which is returned to the first servlet. The first servlet can then modify the response as needed and send it back to the client.
Servlet Collaboration can also be achieved using other mechanisms such as include and redirect. In include, the output generated by the included servlet is added to the output generated by the calling servlet, while in redirect, the client is redirected to a new URL, which can be handled by a different servlet.
Servlet Collaboration is useful in a variety of scenarios, including generating complex responses that require input from multiple sources, sharing resources and data between servlets, and handling requests that require multiple steps or stages. It is a powerful feature of Java Servlet technology that enables developers to build complex, dynamic web applications.
Q29. What is spooling?
Spooling stands for "Simultaneous Peripheral Operations On-line". It is a technique used in computer systems to store data temporarily in a buffer or queue before sending it to an output device such as a printer or a disk. Spooling allows multiple programs to share a single input/output device by placing their output data in a queue and processing it in a first-in, first-out manner. This ensures that each program's output is processed in the order it was received, preventing conflicts and ensuring that each program gets its output in a timely and efficient manner.
Spooling is commonly used to manage print jobs in operating systems. Instead of sending a print job directly to a printer, the operating system spools the print job to a print spooler, which then queues the job for printing. The spooler manages the order in which the jobs are printed and ensures that all jobs are printed without interruption, even if the printer is busy with another job.
Spooling has several benefits, including improving the performance of input/output operations by buffering data and allowing multiple programs to share a single device without conflicts. It also provides fault tolerance and error recovery by ensuring that data is not lost if a device fails or crashes.
Overall, spooling is an important technique used in computer systems to manage input/output operations and improve the performance and reliability of data processing.
Q30. What is a data structure?
A data structure is a way of organizing and storing data in a computer program so that it can be accessed and manipulated efficiently. It defines a specific way of organizing data in memory, providing algorithms for accessing, searching, and manipulating that data.
Data structures can be simple or complex, and they are often designed to support specific operations and algorithms. Examples of common data structures include input arrays, linked lists, input lists, input strings, stacks, queues, trees, graphs, and hash tables.
Data structures are an essential part of computer programming, as they provide efficient ways of storing and manipulating data, and they play a critical role in the development of algorithms and data processing applications. Choosing the right data structure for a given problem is important for achieving the best possible performance and efficiency.
Q31. What is a binary tree data structure?
A binary tree is a type of data structure in which each node has at most two children, referred to as the left child and the right child. Each node in a binary tree contains a value or a key, and each node's left child has a value less than the node itself, while its right child has a value greater than the node itself.
A binary tree is typically represented as a rooted tree, with a single root node at the top of the tree and all other nodes arranged in a hierarchical fashion below it. The root node has no parent node, while all other nodes have exactly one parent node.
Binary trees are commonly used in computer science and programming for a variety of purposes, such as searching, sorting, and data processing. Some common operations that can be performed on binary trees include searching for a specific node or value, inserting new nodes, deleting nodes, and traversing the tree in various orders.
There are several types of binary search trees, including binary search trees, AVL trees, and red-black trees, each with their own specific characteristics and algorithms for manipulating the data stored within them. Binary trees are a fundamental data structure in computer science and are used in many different types of applications.
Q32. What do you understand by the longest common subsequence?
In dynamic programming, a common subsequence of two or more strings is a sequence of characters that appears in the same order in each string, but not necessarily consecutively. The longest common subsequence (LCS) of two strings is the longest subsequence that is present in both of them.
For example, consider the two strings "ACCGGTCGAGTGCGCGGAAGCCGGCCGAA" and "GTCGTTCGGAATGCCGTTGCTCTGTAAA". One possible LCS of these two strings is "GTCGTCGGAAGCCGGCCGAA", which is a subsequence that appears in both of the strings and is of maximal length.
Finding the LCS of two strings is a common problem in computer science and has applications in areas such as bioinformatics, where it can be used to compare DNA sequences, and in text processing, where it can be used to detect plagiarism or similarities between documents. There are efficient algorithms to solve this problem, such as dynamic programming, which can find the LCS of two strings in O(mn) time, where m and n are the lengths of the strings.
Uber Interview Question: HR Round
As you will see in the Uber recruitment process we have shared below the HR round is the final stage you have to cross, which might lead you to get a job at the company. In this section, we will look at some questions that you might come across in this round.
Q33. What are some of your strengths and weaknesses?
Many candidates might be on the edge about mentioning their weaknesses to an interviewer. But the intention of the Uber interviewer here will be to assess how aware you are of yourself and how you are working to overcome your weakness. After all, everyone has them. Also, what many tend to do when sharing their strengths is to sound boastful, which is certainly not the way to go. The idea here is to find the right balance and frame the perfect answer. Below is a sample answer to this question.
Sample answer-
Everyone has some strengths and weaknesses, and I also possess them. My strength is that I can be focused on a single project for a long time. My weakness is that I don't communicate while I am involved in a project, but it is more of a help that I don't lose focus. Now I am working on improving my communication skills.
Q34. What is the reason behind your wanting to join Uber?
We all know that one must research the company properly before appearing for an interview. And it is questions like this where your research will come to benefit you. Use all the knowledge you have compiled and frame an honest answer as to why you want to be a part of the Uber team.
Sample answer:
Uber gives a lot of opportunities to software development engineers. It is the perfect place to try out things that I have learned from college and relevant work experience.
Q35. What do you know about Uber? Or give a brief intro of the company in your own words.
This is another Unber interview question where researching the company before the interview can make (or break) your answer.
Sample answer:
Uber is one of the fastest-growing companies in the world and uses cutting-edge technology for its user interface. Uber is also among those companies which have one of the biggest mobile subscriber bases in the world.
Q36. Why should we hire you? Or, What value would you bring to Uber?
This is one of the most common HR round interview questions, and for good reason. Your answer will give the interviewer an insight into your POV and your personality. It is best to prepare an answer beforehand, a sample of the same is given below.
Sample answer:
When I come to Uber, I will be bringing my focus and perception to the team. I can get a macro-view and a micro-view of things, so yeah, this will be my contribution which will help others in properly analyzing things and finalizing the approach.
In the world that we live in today, many jobs require you to shift bases and not just once. In this case, the only advice we have is to be 100% honest. If you are okay with moving, then say so, and if not, then let the interviewer know. Also, state any conditions you have for moving up front. While the interviewer has asked this question, they may not necessarily want you to relocate.
Sample answer-
Yes, I am prepared to relocate to any part of the country as long as the designation is up to my expectation.
The key to answering such subjective questions is to keep them brief yet informative. Ideally, you must give a gist of your personality and work experience while showcasing why you are the perfect fit for the role and the company.
Sample answer:
I am a software developer who loves to build minimalistic apps whose functionality is maximum, with the number of components being minimal. I am also a team player who loves to contribute to every project assigned.
Another company-specific question that you might come across in an interview with Uber. The intent of the question is to assess your motivations to apply for the job at the company. The interviewer might also be looking to assess if you are company-fit or not by asking this question. So frame a thoughtful, concise, and clear answer before appearing for the interview.
Sample answer:
Uber has always been the kind of organization that has invested in its workforce and allows everyone to contribute, irrespective of their positions. This is what drew me to Uber.
Q40. Tell us about any of your personal projects that you worked on.
The intent behind the interviewer asking you this question is most probably to assess your knowledge in the domain, the kind of projects you have worked on, and the value that you can add to the company if hired. The best way to tackle these questions is to mention some projects that you are most proud of and to quantify your achievements in the same.
Sample answer:
I have developed an app that incorporates both features of a food delivery app which was made on a points-based system, just like the travel points in an aircraft. After collecting a certain number of points, the subscribers get a free meal.
Q41. Any tough decisions you have made in your career?
One of the key skills that every company wants their employees to possess is problem-solving and decision-making abilities. The intent of this question is most probably to see if you are the right fit under these conditions. The best way to answer this question is to explain a particular situation you were faced with either in your educative years or previous job and then showcase how you broached the topic and made difficult decisions when the situation called for it.
Sample answer:
I was working in an internship during college where the job role was that of a data entry clerk instead of a software developer. The employers had specifically mentioned that it would be a software development role. But all I got to do was fill the code in a code snippet. I had to ponder a lot of this job role was beneficial to my career. After much deliberation, I decided to quit as I was not learning anything new. This is one of the toughest decisions in my career.
Q42. What do you know about Uber's recent developments?
The intent behind the interviewer asking this company-specific question is to see how company-aware you are. This is why you must research the company properly, read recent news, visit the website, and explore its social media channels to gather info beforehand. Then use the information to frame the perfect answer for this question.
Sample answer:
Uber has been investing a lot in logistics and supply chain management. So, it has been also upgrading its workforce with the help of SAP, which is sharing software and training people in these areas.
This brings us to the end of your list of top Uber interview questions that you must prepare for if you want to increase your chances of landing a job here. Now let's have a look at the whole recruitment process that almost every applicant at Uber must go through.
The Uber recruitment process consists of 4 primary rounds, namely-
Online Test Round
Technical Interview (Online/ Onsite)
System Designing Round
Human Resources Round or HR Round.
Each of these rounds might further consist of sub-rounds depending upon the job profile and the requirements for the same. However, the basic interview process remains the same.
To begin with, you will have to apply for the respective job position that you are interested in and fulfill basic formalities (like telephone screening, etc.) before the real interview process begins.
Online Test/ Coding Round: The online test conducted by Uber varies in difficulty from medium to hard and is an elimination round. The intent here is to critically evaluate your problem-solving ability in a timely manner. The questions center on topics like DSA, distributed database management systems, etc., and languages like Java, C++, Python, etc. However, this is a simple round that might be optional for candidates with relevant work experience.
Technical Interview Round: This round usually consists of onsite interviews; however, it might be carried out online, depending upon the situation. This round is a series of 4-6 technical/ coding interviews. In these onsite interviews, you will either be asked to solve coding problems or even provide whiteboard solutions. The questions will span topics including (but not limited to)-
DSA (data structures and algorithms), DBMS (database management systems), operating systems, networks (public network, virtual private network, etc.), object-oriented programming (OOPs) concepts, linear regression, binary tree/ binary search tree/ search entire tree, the array of integers and strings, queue & dequeue operations, memory management/ memory manager, and memory reference, legal/ illegal memory access, primary/ secondary memory location, input list, etc.
The difficulty level for these rounds progresses gradually, starting from moderate to high, so you must prepare questions accordingly.
System Design Round:
In this interview round, the Uber interviewers will test the candidates on their system design capabilities. The type and difficulty level of questions will vary depending on the individual's previous work experience and the respective job profile. An example problem is- to create a high-level product using OOPs by classifying the significant features of the system and scale it. It will test the candidate's foundational knowledge of load balancing, caching, and other concepts related to product development & design.
HR/ Managerial Round:
This is the last round of the process wherein the interviewer's main intent is to assess if the candidate fits in the company culture or not. It will consist of questions related to prior/ relevant work experience along with behavioral interview questions. It is ideal to prepare for behavioral questions well, as they help the company assess your personality and behavioral traits. The interviewer will also look at your communication skills. The panel for this round might consist of cross-functional team members. For example, if you are interviewing for a product profile, the panel might consist of the product manager and team members.
Uber was founded by Garrett Camp and Travis Kalanick in March 2009. The chairman of Uber is Ronald Sugar, and the CEO is Dara Khosrowshahi. The company is headquartered in San Francisco with multiple centers in India (Bengaluru, Gurgaon, and Hyderabad). The tech company provides a wide array of mobility services, including car/ cab rides, food and package delivery, couriers, and freight transportation. It is constantly working to meet the needs of all its customer segments. It has expanded its product portfolio to include electric bicycle and motorized scooter rental services.
Uber always aims to design and use cutting-edge technological solutions. It is always on the lookout for candidates with impeccable technical skills, problem-solving abilities, and development skills to fill various positions like software engineer, backend engineer, frontend engineer, etc. They aim to come up with optimal solutions to various real-life problems with the help of technology and functional code in their system. It is definitely an amazing company to work at, both for new and experienced engineers. The Uber interview questions listed in this article are sure to help you in landing a job here.
I am an economics graduate using my qualifications and life skills to observe & absorb what life has to offer. A strong believer in 'Don't die before you are dead' philosophy, at Unstop I am producing content that resonates and enables you to be #Unstoppable.
When I don't have to be presentable for the job, I'd be elbow deep in paint/ pencil residue, immersed in a good read or socializing in the flesh.
Comments
Add comment