Ios engineer Interview Questions
5K
Ios Engineer interview questions shared by candidates
Phone interview question # 1: Given an array (for example, [ 1, 0, 2, 0, 0, 3, 4 ]), implement methods that 1. returns the number of non-zero elements (4) 2. moves the non-zero elements to the beginning of the array (the rest of the elements don't matter) -> both [ 1, 2, 3, 4, 0, 0, 0] and [ 4, 1, 3, 2, X, Y, Z ] are valid
15 Answers↳
let givenArray = [1,0,2,0,0,3,4] var arrayWithNonZeroElements = givenArray.filter({ $0 != 0 }) let arrayWithZeroElements = givenArray.filter({ $0 == 0 }) print(arrayWithNonZeroElements.count) //"4\n" arrayWithNonZeroElements.appendContentsOf(arrayWithZeroElements) print(arrayWithNonZeroElementst) // [1,2,3,4,0,0,0] Less
↳
The answer from OP is good, but there is a case where it doesn't work : if the last value of the array is @0 and the array contains another @0 (Ex: [@1, @0, @2, @0], then you end up swapping two @0 and not solving fully the problem. There is a little optimization possible on the ending condition of the for loop : ending when we reach exchangeObjectAtIndex:indexOfLastNonZeroItem instead. Here is my full solution : - (NSInteger) countAndRearrangeNonZeroElementsFromThisArray: (NSMutableArray*) originalArray { NSInteger countOfZeros = 0; NSInteger indexOfLastNonZeroItem = [originalArray count] - 1; while ([originalArray[indexOfLastNonZeroItem] isEqualToNumber: @0]) { indexOfLastNonZeroItem--; } for(NSInteger index = 0; index < indexOfLastNonZeroItem; index++) { NSNumber * numberFromArray = [originalArray objectAtIndex:index]; if([numberFromArray isEqualToNumber:@0]){ countOfZeros++; [originalArray exchangeObjectAtIndex:index withObjectAtIndex:indexOfLastNonZeroItem]; indexOfLastNonZeroItem--; } } return countOfZeros; } Less
↳
modified version of the above answer, that works with inout arrays func countZerosAndMoveToBegning(array: inout [String]) -> UInt { let nonZeros = array.filter { $0 != "0" } let zeros = array.count - nonZeros.count let arrayZeros = Array(repeating: "0", count: zeros) array.removeAll() array.append(contentsOf: arrayZeros) array.append(contentsOf: nonZeros) return UInt(zeros) } Less

Given an array, without using extra space, move all zeros to the end and no-zeros to the beginning. The function should return the number of non-zeros.
14 Answers↳
-(int)sortZerosAndReturnCountOfThem:(NSMutableArray *)arr { NSLog(@"before: %@", arr); int cursorFromStart = 0; int cursorFromEnd = (int)arr.count - 1; while (cursorFromStart < cursorFromEnd) { while (arr[cursorFromStart].intValue != 0) { cursorFromStart++; } while (arr[cursorFromEnd].intValue == 0) { cursorFromEnd--; } if (cursorFromStart < cursorFromEnd) { arr[cursorFromStart] = arr[cursorFromEnd]; arr[cursorFromEnd] = @(0); } } NSLog(@"after: %@", arr); int counter = 0; for (NSNumber *num in arr) { if (num.intValue == 0) { counter++; } } NSLog(@"counter: %d", counter); return counter; } Less
↳
func moveZeros(input: inout [Int]) -> Int { //reverse sort input = input.sorted { $0 > $1 } let countNonZero = input.filter { $0 != 0 }.count return countNonZero } Less
↳
No need to sort. Can do in O(n) time. Swift: func moveAllZerosToFront(list: inout [Int]) -> Int { var numOfZeros = 0 for i in 0.. Less

Verify that a binary search tree is indeed a binary search tree.
12 Answers↳
The idea is if we traverse binary search tree "in-order", output of number is in ascending orders. So here it goes. Not checked for syntax errors, but should work. BOOL Inorder(NODE *node) { static NODE *prev = NULL; // Do need to initialize this as statics are zeroed memory. if (node == NULL) { return true; } if (false == Inorder(node->left)) { return false; } if (prev && node->num num) { return false; } prev = node; return Inorder(node->right); } Less
↳
A simpler approach is to do an inorder traversal keeping track of last seen element. If it is always increasing then we can prove that tree is BST. Less
↳
class TreeNode { var value: Int? var leftChild: TreeNode? var rightChild: TreeNode? } func isBST(node: TreeNode, min: Int, max: Int) -> Bool { print("value: " + String(node.value!)) print("min: " + String(min)) print("max: " + String(max)) if node.value! max { return false } if let leftChild = node.leftChild { if isBST(leftChild, min: min, max: node.value!) == false { return false } } if let rightChild = node.rightChild { if isBST(rightChild, min: node.value!, max: max) == false { return false } } return true } // Creating BST let minValue = Int.min let maxValue = Int.max let node2 = TreeNode() node2.value = 2 node2.leftChild = nil node2.rightChild = nil let node7 = TreeNode() node7.value = 7 node7.leftChild = nil node7.rightChild = nil let node11 = TreeNode() node11.value = 11 node11.leftChild = nil node11.rightChild = nil let node15 = TreeNode() node15.value = 15 node15.leftChild = nil node15.rightChild = nil let node5 = TreeNode() node5.value = 5 node5.leftChild = node2 node5.rightChild = node7 let node13 = TreeNode() node13.value = 13 node13.leftChild = node11 node13.rightChild = node15 let node10 = TreeNode() node10.value = 10 node10.leftChild = node5 node10.rightChild = node13 if isBST(node10, min: minValue, max: maxValue) == true { print("Tree is BST.") }else { print("Tree is not BST.") } Less

- Given an array, remove the duplicates and return a unique array keeping the first occurrence of the duplicates and the order. [@2, @1, @3, @1, @2] --> [@2, @1, @3] - how would you implement call for canceling queued blocks with dispatch_after?
12 Answers↳
There is a built in class that already does this. Just use that. NSArray *array; // input array NSArray *result = [[NSOrderedSet orderedSetWithArray:array] array]; Less
↳
the question answered above are definitely not optimized but easy built in function, I doubt thats what the interviewer want, if it's sorted array, it will be easy, we simply keep track of the current number, remove duplicate and move forward, but if it's not sorted, then I think a NSMutableDictionary would be efficient to perform a one time scan from begin to the end, so it's O(n) time and O(n) space. Less
↳
Is it alright if we use NSOrderedSet? Or do they expect you to solve it without using the built-in components. Because with NSOrderedSet, it can be solved in 1 line. Less

Given a list of number 8 4 3 0 6 4 0, move all 0's to start of the list. use minimum sorting rounds
10 Answers↳
swift solution using bucket sort func sortZeroesAtEnd(in array: [Int]) -> [Int] { //pseudo bucket sort var zeroBucket: [Int] = [] var nonZeroBucket: [Int] = [] for n in array { if n == 0 { zeroBucket.append(n) } else { nonZeroBucket.append(n) } } return nonZeroBucket + zeroBucket } Less
↳
var array = [8, 4, 3, 0, 6, 4, 0] var offset = 0 for index in stride(from: array.count - 1, through: 0, by: -1) { if array[index] == 0 { offset += 1 } else { array[(index + offset)] = array[index] if index < offset { array[index] = 0 } } } // result: [0, 0, 8, 4, 3, 6, 4] Less
↳
func moveZerosToFront(array: [Int]) -> [Int] { var resultArray = [Int]() for num in array { num == 0 ? resultArray.insert(0, at: 0) : resultArray.append(num) } return resultArray } Less

How to detect a common superview.
9 Answers↳
- (nullable UIView *)commonSuperview:(nullable UIView *)otherView { if(!otherView) return nil; NSMutableArray* superViewsArray = [NSMutableArray array]; UIView* superVeiw = self; while (superVeiw) { [superViewsArray addObject:superVeiw]; superVeiw = superVeiw.superview; } superVeiw = otherView; while (superVeiw) { if([superViewsArray containsObject:superVeiw]){ break; } superVeiw = superVeiw.superview; } return superVeiw; } Less
↳
extension UIView { func sameSuperview(other: UIView) -> UIView? { guard self.superview != nil || other.superview != nil else { return nil } var superViews: [UIView] = [] //Should be a set var selfSuperView = self.superview while selfSuperView != nil { superViews.append(selfSuperView!) selfSuperView = selfSuperView!.superview } selfSuperView = other.superview while selfSuperView != nil { if superViews.contains(selfSuperView!) { return selfSuperView } selfSuperView = selfSuperView!.superview } return nil } } Less
↳
- (UIView *)commonSuperView:(UIView *)oneView anotherView:(UIView *)anotherView { if (!oneView || !anotherView) { return nil; } NSMutableArray *viewArray = @[oneView].mutableCopy; while (oneView.superview) { oneView = oneView.superview; [viewArray addObject:oneView]; } if ([viewArray containsObject:anotherView]) { return anotherView; } while (anotherView.superview) { anotherView = anotherView.superview; if ([viewArray containsObject:anotherView]) { return anotherView; } } return nil; } Less

given an array of words, how to eliminate the duplicates? You have a simple tree structure Ⓐ and its clone ⓐ. Each node in the tree has a pointer to it's parent as well as an array of its children. Given an original tree's node Ⓑ and cloned tree ⓐ, implement a method that returns ⓑ (the clone of Ⓑ). (Imagine finding the matching UIButton/UISlider/UIView in a separate cloned view controller.) Original Ⓐ ┏━┻━━┓ ◯ ◯ ┏┻┓ ┏━╋━┓ ◯ ◯ ◯ ◯ ◯ ┏┻┓ ┃ ◯ Ⓑ ◯ Clone ⓐ ┏━┻━━┓ ◯ ◯ ┏┻┓ ┏━╋━┓ ◯ ◯ ◯ ◯ ◯ ┏┻┓ ┃ ◯ ⓑ ◯
8 Answers↳
Since nobody answered regarding the UiView tree question, posting my solution that I finished only after the interview: -(void)originalInput { UIView *B = [UIView someViewWithParentAndChildren]; //known subview UIView *a = [UIView someViewWithParentAndChildren]; //root of clone view tree NSMutableArray *indexPaths = [NSMutableArray new]; [self recordIndexPaths:indexPaths fromView:B]; //creating index array UIView *cloneViewB = [self findViewByIndexes:indexPaths forIndex:0 forView:a]; //recursing through the clone view hierarchy NSLog(@"%@", cloneViewB); } -(void)recordIndexPaths:(NSMutableArray *)indexPaths fromView:(UIView *)view { if (view.parent == nil){ return; }else { UIView *parent = view.parent; int i = [parent.children indexOfObject:view]; [indexPaths insertObject:i atIndex:0]; //i is not and object, but primitive, should be incapsulated in NSNumber in real life!! [self recordIndexPaths:indexPaths fromView:parent]; } } -(UIView *)findViewByIndexes:(NSArray *)indexPaths forIndex:(int)i forView:(UIView *)currentView { if (!currentView.children.count) return currentView; int j = indexPaths[i]; //j is not and object, but primitive, should be incapsulated in NSNumber in real life!! UIView *child = currentView.children[j]; return [self findViewByIndexes:indexPaths forIndex:i+1 forView:child]; } Less
↳
// We just need to find the path to the main top superview on the original view, saving the index of each view based on its superview and then reverse the path and search on the cloned view. func findView(_ view: UIView, in clonedView: UIView) { var path = [Int]() var view: UIView? = view while view != nil { let tmp = view! view = view!.superview if let idx = view?.subviews.index(of: tmp) { path.append(idx) } } view = clonedView for idx in path.reversed() { view = view?.subviews[idx] } print("Cloned view is: \(view!.tag)") } Less
↳
func removeDups(words: [String], caseSensitive: Bool = false) -> [String] { var hashtable = Dictionary() var words2 = [String]() for word in words { let hash = (caseSensitive ? word : word.uppercased()).hashValue hashtable[hash] = (hashtable[hash] ?? 0) + 1 if hashtable[hash] == 1 { words2.append(word) } } return words2 } Less

Given nested arrays, write an enumerator class such that next() returns the elements in sequential order, e.g.: [1,[4,3],6,[5,[1,0]]] -> 1, 4, 3, 6, 5, 1, 0 also implement allObjects for this class
8 Answers↳
[1,[4,3],6,[5,[1,0]]] -(void)printOutLinearly:(NSArray *)inpA { if (!inpA.count) NSLog(@”There’s nothing in this array you silly willy”); for (int i=0; i < inpA.count; i++) { if ([inpA objectAtIndex:i] isKindOfClass:[NSArray class]]) { [self printOutLinearly:[inpA objectAtIndex:i]; } else { NSLog(@”%@”,[inpA objectAtIndex:i]; } } } Less
↳
Used an array ivar as a stack to maintain state.
↳
func flattenArray(nestedArray: [Any]) -> [Int] { var myFlattenedArray = [Int]() for element in nestedArray { if element is Int { myFlattenedArray.append(element as! Int) } else if element is [Any] { let recursionResult = flattenArray(nestedArray: element as! [Any]) for num in recursionResult { myFlattenedArray.append(num) } } } return myFlattenedArray } Less

Take in an Int array and move all the zeroes to the end in place. It doesn’t matter how the non-zero numbers are ordered. Preferably as efficient and as space efficient as possible. Example: Input : [ 3, 0, 2, 0, 0, 4, 1, 0 ] Accepted Output: [ 4, 2, 3, 1, 0, 0, 0, 0 ]
7 Answers↳
Delete all 0s while counting them, and then add them to the end. func moveZerosToTheEndInArray(_ array: inout Array) -> Array { var counter = 0 array = array.filter({ (arrayElement) -> Bool in print(arrayElement) if arrayElement == 0 { counter += 1 print("Increment counter because arrayElement is \(arrayElement)") return false } print("return true because arrayElement is \(arrayElement)") return true }) print(array) print(counter) for _ in 0.. Less
↳
func sortedZeroToEnd(_ arr:[Int]) -> [Int] { return arr.sorted{ $0 > $1 } } Less
↳
What about : let arr = [ 3, 0, 2, 0, 0, 4, 1, 0 ] let res = arr.filter( {$0 != 0} ) + arr.filter( {$0 == 0} ) OR let arr = [ 3, 0, 2, 0, 0, 4, 1, 0 ] var res = arr.filter( {$0 != 0} ) res += Array(repeating: 0, count: arr.count - res.count) Less

If you have a program that runs slow, how will you improve it to run faster?
7 Answers↳
It depends on the application. Is it CPU-bound or I/O-bound? 1. Check all I/O that the application does: look at I/O speeds, blocking vs. non-blocking calls, see how much time CPU is waiting on I/O using iostat. 2. If I/O is ok, look at CPU usage. Profile the application: look at function call timings, see if any function call is taking abnormally long. Look at garbage collection that may be more frequent if program is using a lot of memory, perhaps due to a memory leak. Less
↳
@Vishal, I've always heard the first rule of performance optimization is don't - until you're absolutely sure what needs to change. Randomly changing code/guessing is a great way to waste time and possibly make things worse, or not find any gains. Profile, analyze, figure out where the time is spent before touching any code! TI's response is the best one I think. Less
↳
I don't know