链表
单链表的反转:
q = head ;
p = null;
r = head.next;
while(q ){
q.next = p;
p = q;
q = r;
r = r.next;
}
单链表的两两互换
p = null;
q = head;
r = head.next;
while(q && r){
p.next = r;
q. next = r.next;
r.next = q;
p = q;
q = q.next;
r = q.next;
}
判断一个链表是否有环:
1. 遍历链表看是否能遍历到null;
2. 遍历链表,一个节点是否出现多次;
3. 快慢指针:
fast = head;
slow = head;
while(fast && slow){
fast = fast.next.next;
slow = slow.next;
if(slow == fast){
return ture;
}
}
return false;
栈
字符串正确判断
int function( a[ ]){
char stack [ ] = { };
int flag = -1, i = 0;
while(a[i]){
if(a[i] == "{" || a[i] == "(" || a[i] == "["){
stack[++flag]=a[i];
}
else if(flag < 0){
return flase;
}
else if(a[i] = stack[flag]+1|| a[i] == stack[flag] +2) {
stack[flag--] = 0;
}
else
return false;
i++;
}
return ture;
}
利用栈实现队列的机制
stack stack1,stack2;
stack1.push(数据流输入);
stack2.push(stack1.pop);
stack2.pop;
堆
判断数据流(str)中第k大元素
1. 建立k大的数组,排序。
2. 优先队列(建立大小为k的小堆)
int heap[ k];
while(str[i]){
if( heap.length < k){
heap.push(str[i]);
}
if(str[i] >heap.top){
heap.pop;
heap.push(str[i]);
}
i++
}
return heap;
返回大小为k的滑动窗口的最大值
int function(*str,k){
if(! str){
return flase;
}
int a[],b[],j= 0,m;
for (int i=0,l=0; i < str.length; i ++ ){
if(i - k >= 0){
b[m++] = str[a[j]];
}
if(i >= k && a[j] <= i - k){
a[j++] =0;
}
while(str[i] > str[a[j]] && l >0 ){
a[j++] = 0;
}
a[l++] = i;
}
return b[];
}
list map 和 set : map和set一般用于计数和查询
判断两字符串是否为异位字符串
1. 将两字符串排序后,判断两字符串是否大小相等。
2. 哈希表:map计数
int function(*str,*str1){
int map[26] = {0};
while(str){
map[ *str - 'a'] += 1;
str++;
}
while(str1){
map[ *str1 - 'a' ] -= 1;
str1++;
}
while(map){
if(*map != 0){
return flase;
}
}
return ture;
}
两数相加
1. 双for暴力解法 时间复杂度为n的平方
2. set查询
三个数相加
1. 三for暴力解法
2. set查询
3. 先排序,后for循环找一个数,然后两指针分别指向头和尾
2:
int threeSum(*nums){
if (len(nums) < 3){
return error;
}
res = set( );
for(int i = 0 , v = 0; i< length.nums - 2; i ++){
int b[10];
v = nums[i];
for(int x = 0, j =i + 1; j < length.nums - 1; j++){
if(b[x] != 1){
b[-v-x] = 1;
}
else{
res.add((v , -v-x . x));
}
}
}
}
判断一棵树是否为二叉搜索树
1. 中序遍历,判断当前节点值是否大于上一节点值。
2. 递归
1:int isvalidBST(*root){
int * p = null;
return helper(root);
}
int helper(* root){
if(root == null){
return true;
}
helper(root.left);
if(p && p. val > root.val){
return false;
}
p = root;
return helper(root.right);
}
2: int isvalidBST(root,min,max){
if(root == null){
return true;
}
if(min != 0 && root.val <= min){
return false;
}
if(max != 0 && root.val >= max){
return false;
}
return isvalidBST(root.left, root.val,0) && isvalidBST(root.right,0,root.val);
}
最近的公共祖先
1. 寻找路径(记下路径找到公共节点)
2. 递归
2:int lowestCA(*root,treeNode p, treeNode q){
if(root == null || root == p || root == q){
return root;
}
right = lowest(root.right , p ,q);
left = lowest(root.left, p, q);
if(right != null && left != null){
return root;
}
else if(left != null ){
return left;
}
else(right != null){
return right;
}
if(right == null && left == null){
return null;
}
}
递归
递归一般用于解决子问题不冲突的问题,子问题冲突则一般用动态规划
求x的n次方
1. 暴力法
2. 分治法
int pow(x,n){
if(n== 0){
return 1;
}
if( n % 2){
return x * pow(x, n -1);
}
if( n < 0){
return pow(1/x , -n);
}
if(n % 2 == 0 ){
return pow(x*x , n/2);
}
}
求众数(出现次数大于n/2的数)
1. 暴力法 双循环O(n*n)
2. map:{x,countx} O(N)
3. sort 下标为n/2的必定是众数 快排O(nlogn)
4. 分治 把数组分两边,分别找左边的众数和右边的众数
5. 投票算法
4: int fz(*nums,int start,int end){
if(start == end){
return nums[start];
}
right = (nums,n/2 +1 , n);
left = (nums, 0 , n/2);
if(right == left){
return left;
}else
return max(count(left),count(right));
}
贪心算法
子问题的最优解能推到最终问题的最优解(金额问题,面值互相为整数倍)
动态规划会保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能
深度优先搜索(DFS)
用递归写(栈)
int dfs(*root){
if(!root){
return false;
}
array[i++] = root.val;
if(root.left != null){
dfs(root.left);
}
if(root.right != null){
dfs(root.right);
}
}
广度优先搜索(BFS)
用队列写(队列)
一层一层递进
int bfs(start,end){
queue = [ ] ;
queue.push( start);
visited.add(start);
int depth = 0;
while (queue){
depth++;
for(int n = length(queue), i = 0; i < n; i++){
node = queue.pop;
visited.add(node);
if(node.right != null && node.right not in visited){ //树不需要考虑这种情况
queue.push(node.right);
}
if(node.left != null && node.left not in visited){ //树不需要考虑这种情况
queue.push(node.left);
}
}
}
}
二叉树的最大和最小深度
1. bfs
2. dfs
3. 递归
1:int mindepth(*root){
queue = [ ];
queue.push(root);
int level = 0;
while(queue){
level ++;
for(int i = 0, j = length.queue; i < j;i++){
node = queue.pop;
if(!node.right && !node.left){
return level;
}
if(node.right){
queue.push(node.right);
}
if(node.left){
queue.push(node,left);
}
}
}
}
3: int depthmax(*root){
if(root == null){
return 0;
}
return max(depthmax(root.left),depthmax(root.right)) + 1;
}
int depthmin(*root){
if(root == null){
return 0;
}
left = depthmin(root.left);
right = depthmin(root.right);
return min(left ,right)+1;
}
生成有效括号组合
递归(分治)
char sckh(n){
char a [maxsize];
a= scyxkh(0 , 0 , n,"");
return a;
}
scyxkh(left,right,n,result){
if(left == n && right == n){
return result;
}
if(left < n ){
return scyxkh(left +1 , right , n ,result + "(");
}
if( right < n && right < left){
return scyxkh(left, right +1 , n , result + ")");
}
}
N皇后问题
DFS递归
solveNQueen( int n){
if( n < 1){
return false;
}
int lie = set();
int pie =set();
int na = set();
nqueen(0, n , lie );
}
int nqueen(int row , int n, int *result){
if(row == n){
return result;
}
for (int i= 0; i < n ; i ++){
if(i not in lie && (row - i) not in na && (row + i) not in pie ){
lie.append(i);
pie.append(row + i);
na.append(row - i);
nqunne(row+1,n, lie);
lie.remove(i);
pie.remove(row + i);
na.remove(row - i);
}
}
}
数独:
dfs递归
加速方法①对数独中要填的空进行排序预处理
②优先可选择少的空
int board[9][9]={};
int sd(board){
for(int i = 0; i < 9 ; i ++){
for(int j = 0; j < 9; j++){
if( board[i][j] == " "){
for(k= 1; k < 10 ; k++){
if(available(i , j , k)){
board[i][j] = k;
if(sd(board)){
return true;
}
else board[i][j] = " ";
}
}
return false;
}
return true;
}
}
}
available( int i, int j, int k){
for(int l = 1; l < 10 ; l++){
if(board[i][l] == k){
return false;
}
if(board[l][j] == k ){
return false;
}
if(board[ (i/3) *3 + l %3 ][(j /3) *3 + l %3 ] == k ){
return false;
}
}
return true;
}
二分查找法:
int function(n , left , right){
while(right > = left){
int mid = (left + right)/2;
if(a[mid ]== n){
return true;
}
if( a[mid] > n){
right = mid -1;
}
if( a[mid] < n){
left = mid +1;
}
}
return false;
}
求为1的位数
1. if (x & 1== 1){
count ++;
}
x= x >>1;
2. x = x & (x -1) //每次将最后一位1打掉
while(x ! = 0){
count ++;
x = x & (x -1);
}
判断一个数是否为2的幂次方
1. 不断mod 2
function(int n){
while( n != 2){
if( n % 2 == 1){
return false;
}
n= n /2;
}
return true;
}
2. 位运算
funtion(int n){
if(n & (n -1) == 0 && n != 0){
return true;
}
return false;
}
把0 到 n的二进制数1的个数存进数组
1. 数出每个二进制数位为1的个数
int *function(int n){
int count[MAX]={};
for(int i = 1;i < =n ; i++){
int j = 0;
while(i){
i = i&(i -1);
j++;
}
count[i] = j;
}
return count;
}
2. 利用前面结果,位运算做下标
int *function(int n){
int count[MAX]= {};
for(int i =1; i< = n; i++){
count[i] += count[i &(i -1)] + 1;
}
return count;
}
位运算解决N皇后问题
void DFS(int row,int col,int pie,int na){
if(row >= N){ // 递归终止条件
count++;
return;
}
int bits = (~(col | pie | na)) & ( (1 << n) -1 ); // 得到空位
while(bits > 0){ //bits不为空
int P = bits & -bits;//得到最后一位“1”
DFS(row+1,col | P, (pie | P) << 1, (na | P) >> 1); //下层递归
bits &= bits -1; //删去最后一位“1”
}
}
动态规划
爬楼梯
1. 回溯得出递推公式
2. 列出状态方程
3.dp
int function(int n){
if(n == 0 || n == 1 || n == 2){
return n;
}
int f[N] = {1,2};
for(int i = 2; i< n; i++){
f[i] = f[i-1] + f[i-2];
}
return f[n-1];
}
三角形最小路径和
① DFS
② 贪心(不可行)
③ DP
③:int function(int *board,m,n){
int mini[N]={0};
for(int i = 0; i < n; i++){
mini[i] = board[m][i];
}
for(int j = m-1 ; j>= 0 ; j--){
for(int k = 0; k <sizeof(board[j][]); k++){
mini[k] = board[j][k] + min(mini[k],mini[k+1]);
}
}
return mimi[0];
}
乘积最大子序列
①递归
②DP
②:1.列出状态方程
2. 递推公式
int function( int * nums){
if(!nums){
return 0;
}
int dp[sizeof(nums)][2] = {1,1};
int res = 0;
for(int i = 1; i < length.nums;i++){
if(nums[i] > 0){
dp[i][0]= dp[i-1][0] * nums[i];
dp[i][1] = dp[i-1][1] * nums[i];
}
else{
dp[i][0] = dp[i-1][1] * nums[i];
dp[i][1] = dp[i-1][0] * nums[i];
}
res = max(dp[i][0],res);
}
return res;
}
滚动数据
x = i%2;
y = (i-1)%2;