算法笔记

10 篇文章 0 订阅
8 篇文章 0 订阅

1.如何判断一个链表是否有环

经典解法是快慢指针,没有之一

typedef struct _Link{
	Node *head;
	int data;
} Link;
typedef struct _Node{
	struct _Node *next;
	int data;
}Node;
int checkCircle(Link *link){
	Node *fast, *slow;
	if(link->head == NULL)return 0;
	fast = link->head;
	slow = link->head;
	while(1){
		if(fast->next == NULL)return 0;
		if(slow->next == NULL)return 0;
		if(fast == slow)return 1;
		fast = fast->next->next;
		slow = slow->next;
	}
}

2.反转一个链表

主要考察对单链表指针指向的先后顺序的操作,理论很简单,代码有点技巧

void reverseChain(Link *link){
	Node *prev, *cur, *next;
	if(link->head == NULL)return;
	cur = link->head;
	prev = NULL;
	
	while(1){
		if(cur == NULL)return;
		next = cur->next;
		
		cur->next = prev;
		prev = cur;
		cur = next;
	}
}

3.判断括号字符串是否有效

主要考察对栈的使用,左括号入栈,只要发现右括号就出栈匹配,匹配不成功或者最后栈不空都说明字符串不合法

function isValid($str){
	$stack = [];
	$map = [')'=>'(', ']'=>'[', '}'=>'{'];
	for($i=0; $i<strlen($str);$i++){
		if(in_array($str[$i], $map))array_push($stack, $str[$i]);
		if($map[$str[$i]]){
			if(count($stack)==0)return false;
			if(array_pop($stack) != $map[$str[$i]])return false;
		}
	}
	return count($stack)==0;
}

4.用队列实现栈&用栈实现队列

function stack2queue(){
	var input = [], output = [];
	return {
		push: function(v){
			input.push(v);
		},
		pop: function(){
			if(output.length>0)return output.pop();
			while(input.length>0){
				output.push(input.pop);
			}
			return output.pop();
		},
		length: function(){
			return input.length + output.length;
		}
	}
}

5.返回数据流中的第K大元素

考察对堆排序的应用

#include <stdio.h>

void swap(int *arr, int i, int j){
	int temp = arr[i];
	arr[i] = arr[j];
	arr[j] = temp;
}

void printArr(int arr[], int len){
	printf("==================================================================\n");
	for (int i = 0; i < len; i++)
	{
		printf("%4d", arr[i]);
		if (i != (len - 1))printf(",");
	}
	printf("\n==================================================================\n");
}

void HeapAdjust(int arr[], int p, int endIndex){
	int i, tmp;
	tmp = arr[p];
	for (i = 2 * p + 1; i <= endIndex; i = i * 2 + 1){
		if (i < endIndex && arr[i] < arr[i + 1])i++;
		if (arr[p]>arr[i])break;
		arr[p] = arr[i];
		p = i;
	}
	arr[p] = tmp;
}
void HeapSort(int arr[], int endIndex){
	int i;
	for (i = endIndex / 2; i >= 0; i--){
		HeapAdjust(arr, i, endIndex);
	}
	for (i = endIndex; i >= 0; i--){
		swap(arr, 0, i);
		HeapAdjust(arr, 0, i-1);
	}
}
int *topK(int arr[], int len, int k){
	int res[k], i;
	for(i=0; i<len;i++){
		if(i<k)res[i] = arr[i];
		if(i>=k && res[k-1]<arr[i])res[k-1] = arr[i];
		HeapSort(res, i);
	}
	return res[k-1];
}

6.返回滑动窗口中的最大值

function maxSlidingWindow($arr,$k){
	$window = [];
	$res = [];
	if(empty($arr))return $res;
	for($i=0;$i<count($arr);$i++){
		if($i>=$k && $window[0]<=($i-$k))array_shift($window);
		//以下可以保证$window是一个有序的递减数组,
		while(count($window)>0 && $arr[$i]>=$window[count($window)-1]){
			array_pop($window);
		}
		//$i不论大小都要入栈的,因为还不知道后面的数是大是小呢
		array_push($window, $i);
		if($i>=$k-1)array_push($res, $arr[$window[0]]);
	}
	return $res;
} 

7.找出一个数组中有两数之和为k的组合

function twoSum($arr, $k){
	$set = [];
	$res = [];
	foreach($arr as $key => $n){
		$t = $k-$n;
		if(in_array($t, $set)){
			$res[] = [$t, $n];
		}else{
			array_push($set, $n);
		}
	}
	return $res;
}

8.找出一个数组中三数之和为k的组合

function threeSum($arr, $k){
	$set = [];
	$res = [];
	if(count($arr)<3)return $res;
	
	foreach($arr as $ak=> $a){
		foreach($arr as $bk=> $b){
			if($bk<=$ak)continue;
			$c = $k-$a-$b;
			if($set[$c]){
				$res[] = [$a, $b, $c];
			}else{
				$set[$a] = 1;
			}
		}
	}
	return $res;
}

9.判断一棵树是否是二叉排序树

int isValideNode(Node *root, Node *prev){
	if(root == NULL)return 1;
	if(isValidNode(root->left, prev)==0)return 0;
	if(prev != NULL && prev->val > root->val)return 0;
	prev = root;
	return isValidNode(root->right, prev)
}
//第一种算法是用一个prev指针
int isValidBST(Node *root){
	Node *prev = NULL;
	return isValidNode(root, prev);
}
//第二种算法是用限定边界法
int isValidBST2(Node *root, Node *min, Node *max){
	if(root == NULL)return 1;
	if(min != NULL && root->val<min->val)return 0;
	if(max != NULL && root->val>max->val)return 0;
	return isValidBST2(root->left, min, root->val) &&
	isValidBST2(root->right, root->val, max);
}

10.二叉搜索树的最近公共祖先

//以下针对普通的树
Node *findPOrQ(Node *root, Node *p, Node *q){
	if(root == p || root == q || root == NULL)return root;
	Node *left = findPOrQ(root->left, p, q);
	Node *right = findPOrQ(root->right, p, q);
	return left == NULL ? 
		right: (right == NULL? left: root);
}
//以下针对二叉搜索树
Node *findPOrQ2(Node *root, Node *p, Node *q){
	if(p->val <root->val && root->val>q->val)
		return findPOrQ(root->left, p, q);
	if(p->val>root->val && root->val<q->val)
		return findPOrQ(root->left, p, q);
	return root;
}
//以下是针对搜索树的迭代实现
Node *findPOrQ3(Node *root, Node *p, Node *q){
	while(root != NULL){
		if(p->val<root->val && root->val>q->val)
			root = root->left;
		if(p->val>root->val && root->val<q->val)
			root = root->right;
		return root;
	}
}

11.遍历二叉树

//先中后序遍历都是用递归最简单
void postOrder(Node *root){
	if(root != NULL){
		postOrder(root->left);
		postOrder(root->right);
		printf("%d", root->val);
	}
}

12.求x的N次方:pow(x,n)

主要考察分治法

function newPow($x, $n){
	if(!$n)return 1;
	if($n<0)return 1/newPow($x, -$n);
	if($n%2)return x*newPow($x, $n-1);
	return newPow($x*$x, $n/2);
}

13.求众数:给出一个数组,找出其中出现次数最多的一个数

时间复杂度最小的是用map

function findMajority($arr){
	$map = [], $max = 0, $maxNum = 0;
	foreach($arr as $v){
		if(!$map[$v])$map[$v] = 0;
		$map[$v]++;
	}
	foreach($map as $n => $c){
		if($c>$max){
			$max = $c;
			$maxNum = $n;
		}
	}
}

14.广度优先算法

def BFS(graph, start, end):
	queue = []
	queue.append([start])
	visited.add(start)
	
	while queue:
		node = queue.pop()
		visited.add(node)
		
		process(node)
		nodes = generate_related_nodes(node)
		queue.push(nodes)

15.深度优先

visited = set();
def dfs(node, visited):
	visited.add(node)
	for next_node in node.children():
		if not next_node in visited:
			dfs(next_node, visited)

16.求二叉树的最大/小深度

int maxDepth(Node *node):
	if not node:
		return 0
	return 1 + max(maxDepht(node.left), maxDepth(node.right))

int minDepth(Node *node):
	if not node:
		return 0
	if not node.left:
		return 0
	if not node.right:
		return 0
	
	return 1 + min(minDepth(node.left), minDepth(node.right))	

17.写一个函数,使其能生成所有可能的有效括号组合

function genParenthesis(n){
	var res = [];
	var gen = function(left, right, s){
		if(left == n && right == n)return res.push(s);
		if(left<n)gen(left+1, right, s+'(');
		if(left>right && right<n)gen(left, right+1, s+')');
	};
	gen(0, 0, n, '');
	return res;
}

18.二分查找

int binarySearch(int arr[],int len, int s){
	int min=0, max=len-1, mid;
	while(min<=max){
		mid = (min+max)/2;
		if(arr[mid]>s){
			max = mid-1;
		}else if(arr[mid]<s){
			min = mid+1;
		}else{
			return mid;
		}
	}
	return -1;
}
int binarySearch2(int arr[], int min, int max, int s){
	int mid;
	if(min<=max){
		mid = (min+max)/2;
		if(arr[mid]==s){
			return mid;
		}else if(arr[mid]>s){
			return binarySearch2(arr, min, mid-1, s);
		}else{
			return binarySearch2(arr, mid+1, max, s);
		}
	}
	return -1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>