刷题总结 - Array and String
Array
is one of the fundamental blocks in data structure. Since a string
is just formed by an array of characters, they are both similar. Most interview questions fall into this category.
In this card, we will introduce array
and string
. After finishing this card, you should:
- Understand the differences between
array
anddynamic array
; - Be familiar with basic operations in the array and dynamic array;
- Understand
multidimensional arrays
and be able to use atwo-dimensional
array; - Understand the concept of
string
and the different features string has; - Be able to apply the
two-pointer
technique to practical problems.
Introduction to Array
1 | // "static void main" must be defined in a public class. |
Introduction to Dynamic Array
Most programming languages offer built-in dynamic array
which is still a random access list data structure but with variable size. For example, ArrayList
in JAVA.
1 | public class Main { |
Question - Plus One
Given a non-empty array of digits representing a non-negative integer, plus one to the integer.
1 | Input: [1,2,3] |
1 | // 思路: |
Introduction to 2D Array
Similar to a one-dimensional array, a two-dimensional array also consists of a sequence of elements. But the elements can be laid out in a rectangular grid rather than a line.
1 | public class Main { |
Question - Spiral Matrix
Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order.
1 | Input: |
1 | class Solution { |
Question - Pascal's Triangle
Given a non-negative integer numRows, generate the first numRows of Pascal's triangle.
1 | Input: 5 |
1 | class Solution { |
Introduction to String
A string is actually an array of unicode characters
. You can perform almost all the operations we used in an array. You can try it out by yourself.
However, there are some differences.
Compare Function
String has its own compare function (we will show you the usage of compare function in the code below).
Can we use "==" to compare two strings?
It depends on the answer to the question:
Does the language support operator overloading?
- If the answer is yes (like C++), we may use
==
to compare two strings. - If the answer is no (like Java), we may not use
==
to compare two strings. When we use==
, it actually compares whether these two objects are the same object.
1 | // "static void main" must be defined in a public class. |
Immutable or Mutable
Immutable
means that you can't change the content of the string once it's initialized.
- In some languages (like C++), the string is mutable. That is to say, you can modify the string just like what you did in an array.
- In some other languages (like Java), the string is immutable. This feature will bring several problems. We will illustrate the problems and solutions in the next article.
You can determine whether the string in your favorite language is immutable or mutable by testing the modification operation. Here is an example:
1 | // "static void main" must be defined in a public class. |
Extra Operations
1 | // "static void main" must be defined in a public class. |
You should be aware of the time complexity of these built-in operations.
For instance, if the length of the string is , the time complexity of both finding operation and substring operation is .
Also, in languages which the string is immutable, you should be careful with the concatenation operation (we will explain this in next article as well).
Never forget to take the time complexity of built-in operations into consideration when you compute the time complexity for your solution.
Immutable String - Problems & Solutions
You should know whether the string
in your favorite language is immutable or not in the previous article. If the string
is immutable, it will bring some problems. Hopefully, we will also provide the solution at the end.
Obviously, an immutable string cannot be modified. If you want to modify just one of the characters, you have to create a new string.
You should be very careful with string concatenation. Let's look at an example when we do string concatenation repeatedly in a for loop:
1 | // "static void main" must be defined in a public class. |
Notice how slow string concatenation is for Java? On the other hand, there is no noticeable performance impact in C++.
In Java, since the string is immutable, concatenation works by first allocating enough space for the new string, copy the contents from the old string and append to the new string.
Therefore, the time complexity in total will be:
which is .
If you want your string
to be mutable, there are some substitutions:
- If you did want your string to be mutable, you can convert it to a
char array
.
1 | // "static void main" must be defined in a public class. |
- If you have to concatenate strings often, it will be better to use some other data structures like
StringBuilder
. The below code runs in complexity.
1 | // "static void main" must be defined in a public class. |
Question - Add Binary
Given two binary strings, return their sum (also a binary string).
The input strings are both non-empty and contains only characters 1 or 0.
1 | // 位数操作,加法进位问题!!! |
Question - Implement strStr()
Return the index of the first occurrence of needle
in haystack
, or -1 if needle is not part of haystack.
1 | Input: haystack = "hello", needle = "ll" |
1 | Input: haystack = "aaaaa", needle = "bba" |
1 | public int strStr(String haystack, String needle) { |
Question - Longest Common Prefix
Write a function to find the longest common prefix string amongst an array of strings.
If there is no common prefix, return an empty string "".
1 | Input: ["flower","flow","flight"] |
1 | Input: ["dog","racecar","car"] |
1 | public String longestCommonPrefix(String[] strs) { |
Two-pointer Technique - Scenario I !!!
In the previous chapter, we solve some problems by iterating the array. Typically, we only use one pointer starting from the first element and ending at the last one to do iteration. However, sometimes, we might need to use two pointers at the same time to do the iteration.
An Example
Let's start with a classic problem:
Reverse the elements in an array.
The idea is to swap the first element with the end, advance to the next element and swapping repeatedly until it reaches the middle position.
We can use two pointers at the same time to do the iteration: one starts from the first element and another starts from the last element. Continue swapping the elements until the two pointers meet each other.
1 | public static void reverse(int[] v, int N) { |
Summary
To summarize, one of the typical scenarios to use two-pointer technique is that you want to
Iterate the array from two ends to the middle.
So you can use the two-pointer technique:
One pointer starts from the beginning while the other pointer starts from the end.
And it is worth noting that this technique is often used in a sorted array.
Question - Reverse String
Write a function that takes a string as input and returns the string reversed.
1 | Input: "A man, a plan, a canal: Panama" |
1 | public class Solution { |
1 | class Solution { |
Question - Array Partition I
Given an array of 2n integers, your task is to group these integers into n pairs of integer, say (a1, b1), (a2, b2), ..., (an, bn) which makes sum of min(ai, bi) for all i from 1 to n as large as possible.
1 | Input: [1,4,3,2] |
1 | class Solution { |
How to use Two-pointer Technique???
Question - Two Sum II - Input array is sorted
Given an array of integers that is already sorted in ascending order, find two numbers such that they add up to a specific target number.
The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2.
1 | Input: numbers = [2,7,11,15], target = 9 |
1 | public int[] twoSum(int[] num, int target) { |
Two-pointer Technique - Scenario II
Sometimes, we can use two pointers with different steps to solve problems.
An Example
Let's start with another classic problem:
Given an array and a value, remove all instances of that value in-place and return the new length.
If we don't have the limitation of space complexity, it will be easier. We can initialize a new array to store the answer. Iterate the original array and add the element to the new array if the element is not equal to the given target value.
Actually, it is equivalent to using two pointers, one is used for the iteration of the original array and another one always points at the last position of the new array.
Reconsider the Space Limitation
Now let's reconsider the space limitation.
We can use a similar strategy. We still use two pointers: one is still used for the iteration while the second one always points at the position for next addition.
Here is the code for your reference:
1 | public int removeElement(int[] nums, int val) { |
We use two pointers, one faster-runner i and one slower-runner k, in the example above. i moves one step each time while k moves one step only if a new needed value is added.
Summary
This is a very common scenario of using the two-pointer technique when you need:
One slow-runner and one fast-runner at the same time.
The key to solving this kind of problems is to
Determine the movement strategy for both pointers.
Similar to the previous scenario, you might sometimes need to sort the array before using the two-pointer technique. And you might need a greedy thought to determine your movement strategy.
Question - Remove Element
Given an array nums and a value val, remove all instances of that value in-place and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with extra memory.
The order of elements can be changed. It doesn't matter what you leave beyond the new length.
1 | Given nums = [3,2,2,3], val = 3, |
1 | class Solution { |
Question - Max Consecutive Ones
Given a binary array, find the maximum number of consecutive 1s in this array.
1 | Input: [1,1,0,1,1,1] |
1 | class Solution { |
1 | public int findMaxConsecutiveOnes(int[] nums) { |
Question - Minimum Size Subarray Sum
Given an array of n positive integers and a positive integer s, find the minimal length of a contiguous subarray of which the sum ≥ s. If there isn't one, return 0 instead.
1 | Input: s = 7, nums = [2,3,1,2,4,3] |
1 | class Solution { |