Algorithm concepts, arrays, linked lists, stacks, queues
Determine whether a number is 2 to the Nth power?
N & (N-1) == 0 (N > 0)
Calculation problem:
- Leetcode https://leetcode.cn/
- POJ http://poj.org/
algorithm
algorithm concept
Algorithm representative: high efficiency and low storage, small memory footprint, small CPU footprint, fast computing speed
High efficiency and low storage of algorithms: memory + CPU
Two indicators for evaluating algorithms
- Time complexity: the time it takes to run a program O()
- Space complexity: the memory OOM required to run the program
time complexityO(1,logn,n,nlogn,n^2,n^x)
- Constant: O(1) 1 means it is a constant, we use O(1) for all the numbers that can be determined, O(10000)=>O(1)
- Logarithm: O(logn), O(nlogn)
- Linear: O(N) n must be unknown; if n is known O(1)
- Linear logarithm: O(nlogn)
- Square: O(n^2)
- N-dimensional: O(n^n)
how to find time complexity
- There is a bad place
- Where there are network requests (RPC, remote calls, distributed, databases)
Print log at test time
O(1) > O(logn) > O(n) > O(nlogn) > O(n^2) > O(n^n)
The closer to O(1) the lower the time complexity
Constant: O(1)
int a = 1; // 1次O(1)
for(int i = 0; i < 3; i++) {
//这里运行4次
a = a + 1; //这里运行3次
}
Logarithm: O(logn), O(nlogn)
//对数 2^x=n x就是我们运行的次数 => 对数 x=log2(n) = log2n = 计算机忽略常数 => logn => O(logn)
int n = Integer.MAX_VALUE;
int i = 1;
//O(logn)
while (i <= n) {
i = i * 2;
}
//O(nlogn)
for (int j = 0; j < n; j++) {
while (i <= n) {
i = i * 3;
}
}
Linear: O(N)
//线性: O(N) n一定是未知的; 如果n是已知的O(1)
for (i = 0; i < n; i++) {
a = a + 1;
}
Square: O(n^2)
for (i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
a = a + 1; // O(n^2) n*(n+1)/2 => O(n^2) = 1+2+3+4+..+n=n*(n+1)/2
}
}
Tuning
List Sort Bubble Sort < Quick Sort Merge Sort Heap Sort
Classic: linked list, sorting algorithm, binary tree, red-black tree, B-Tree, B+Tree
Advanced: number theory, graph theory
data structure
array
Thinking questions:
- Question 1: Give you a file containing the age data (0~180) of 1.4 billion people in the country, let you count how many people of each age?
Limit the memory of a single machine to 2G + 2G, and do not use ready-made containers, such as maps, etc.
int age[] = new int[180];
a[0]++; // 0 means 0 years old
Using the array subscript, you can also use the subscript to randomly locate a certain data in the array
- Question 2: Why does the subscript of the value start from 0, and the characteristic of the array is a continuous memory address
int arr[] = new int[5];
The memory address applied for is, for example: 10001, 10002, 10003, 10004, 10005
保存数据:a[0] => 10001 ===> 10001 + 0
保存数据:a[1] => 10002 ===> 10001 + 1
保存数据:a[2] => 10003 ===> 10001 + 2
保存数据:a[3] => 10004 ===> 10001 + 3
保存数据:a[4] => 10005 ===> 10001 + 4
- Question 3: What is the memory address of a two-dimensional array?
1 2 3
4 5 6 => 1 2 3 4 5 6 => i*n + j (i是一维数组的长度、j是在列的位置) => 4 => 1*3 + 0 = 3
How to choose between ArrayList and array
- ArrayList is packaged by JDK and does not need to be expanded
- Array deletion and addition are slow O(n), modification and acquisition are fast O(1)
- random access
- subscript
how to choose?
- If you don't know the data size select ArrayList
- If you know the size of the data and are very concerned about the performance of the selection array; you need to pay attention to the out-of-bounds (head and tail)
Java memory is divided into heap memory and stack memory
Heap memory: store new objects and arrays
Stack memory: reference variables
Both the heap and the stack are used to store data
Stack difference:
- The stack is faster
- The memory data of the stack can be shared, mainly storing some basic data types
int a = 3; 在栈中创建变量a, 然后给a赋值,先不会创建一个3而是先在栈中找有没有3
String s1 = "ja";
String s2 = "va";
String s3 = "java";
String s4 = s1 + s2; // java 里面重装了+, 其实调用了 stringBuild, 会new对象
System.out.println(s3 == s4); //false
System.out.println(s3.equals(s4)); //true
linked list
Thinking questions:
- How to design an LRU cache elimination algorithm (linked list)
- Joseph problem (circular linked list): N people form a circle, start counting from the first one, the Mth one will be eliminated, and the last one will be left, and the rest will be killed. For example, N=6, M=5, the order of being killed is 5, 4, 6, 2, 3, 1
Linked list features
- Does not require contiguous memory space
- has a pointer reference
- Common linked list structures: single linked list, double linked list, circular linked list
Singly linked list LinkList
query O(n)
insertion delete O(1)
double linked list
The B+ tree Mysql leaf node is a doubly linked list,
the jump table is very similar to the Mysql B+ tree
circular linked list
A circular linked list is a special kind of singly linked list. The only difference between it and a singly linked list is the tail node. The
tail node of a singly linked list is an empty address.
The tail node of a circular linked list is the head node.
Linked list and array comparison
Inquire
array
- O(1)
linked list
- O(n)
insert/delete
array insertion
- Tail O(1)
- head O(n)
linked list insertion
- head O(1)
- Tail O(1)
- Intermediate O(1*2)
Important difference:
- The array is simple and easy to use. The implementation uses a continuous memory space. The data in the array can be read in advance with the help of the CPU's cache mechanism, so the access efficiency is higher.
- The linked list is not stored continuously in the memory, so it is not friendly to the CPU cache, and there is no way to effectively read ahead.
- The disadvantage of an array is that its size is fixed, and once it is declared, it will occupy the entire continuous memory space. If the declared array is too large, the system may not have enough contiguous memory space allocated to it,
resulting in "out of memory". If the declared array is too small, it may not be sufficient. - Dynamic expansion: The array needs to apply for a larger memory space, and copying the original array into it is very time-consuming. The linked list itself has no size limit and naturally supports dynamic expansion.
Stack - last in first out - LILO
Thinking questions:
- How to design a bracket matching function? the stack
- How to design a browser forward and back function? (Two stacks, one forward and one backward)
- How to implement four arithmetic formulas such as 3+2*5-3? (two stacks, one number, one symbol)
- Code function call sequence
stack features
A stack is a linear list limited to insert and delete operations only at the end of the table, called the top of the stack, and the other end is the bottom of the stack
Inserting new elements into a stack is called pushing, pushing, and pushing, and
deleting elements is called popping and unstacking
The stack is actually a special linked list or array. The array linked list exposes too many interfaces and is prone to errors
public class KuoHaoStack {
public static boolean isOk(String s) {
MyStack<Character> brackets = new ArrayStack<>(20);
char c[] = s.toCharArray();
Character top = null;
for (char x : c) {
switch (x) {
case '{':
case '(':
case '[':
brackets.push(x);
break;
case '}':
top = brackets.pop();
if (top == null) return false;
if('{' == top) {
break;
} else {
return false;
}
case ')':
top = brackets.pop();
if (top == null) return false;
if('(' == top) {
break;
} else {
return false;
}
case ']':
top = brackets.pop();
if (top == null) return false;
if('[' == top) {
break;
} else {
return false;
}
default:
break;
}
}
return brackets.isEmpty();
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
System.out.println("S的输出结果:" + isOk(scanner.next()));
}
}
}
Queue – first in first out – FIFO
thinking questions
- When the task in the thread pool is full, a new task comes at this time. How does the thread pool handle it? What are the specific strategies? How are these strategies implemented?
- Queue: Blocking queue. Take it when you are free, isn't it the take and put, if it is fair, it must be first in first out. This is the queue we are talking about today. At this time we have two ways, one is an infinite queue. (Linked list, don't use it. LinkedBlockingQueue, JDK), there is another kind that is bounded (implemented by arrays), only deal with the size of the space we opened, and continue to throw out more. Integer.MAX=?2^32-1=More than 2.1 billion, but pay attention to the size of this queue, don't make it small. If it is not enough, it will be wasted if it is too big. In some small systems, you know that the amount of data requested is not large, and it can be used.
- Discarding: Do not deal with it, just throw it out.
A queue is a special linear table, which is special in that it only allows deletion operations at the front end of the table and insertion operations at the back end of the table
queue classification
- Sequential (one-way) queue: (Queue) can only insert data at one end and delete data at the other end
- Circular (two-way) queue (Deque): Each end can perform data insertion and deletion operations
to determine whether it is full
- Method 1: add size
- Method 2: (tail+1)%n == head
public class CircleArrayQueue<Item> {
private Item data[];
private int head = 0;
private int tail = 0;
private int n = 0; //数组最大空间
private int size; //当前队列已存个数
public CircleArrayQueue(int cap) {
data = (Item[]) new Object[cap];
n = cap;
}
public void push(Item item) {
if ((tail + 1)%n == head) return; //关键点
data[tail] = item;
tail = (tail + 1) % n; //关键点
}
public Item pop() {
if (isEmpty()) return null;
Item item = data[head];
head = (head + 1) % n;
return item;
}
public boolean isEmpty() {
return head == tail;
}
}