2020必知的20道C++精选算法题分享

1.Leetcode41 数组题:第一个缺失的正整数
class Solution1 {
public:
	int firstMissingPositive(int A[], int n) {
		for (int i = 0; i < n;) {
			if (A[i] == i + 1) {
				++i;
			}
			else if ((A[i] <= i) || (A[i] > n) || (A[A[i] - 1] == A[i])) {
				A[i] = A[--n];
			}
			else {
				swap(A[i], A[A[i] - 1]);
			}
		}
		return n + 1;
	}
};
void test01() {
	int A[] = { 1,5,6,8,18,-1,2,3,4,10 };
	int len = sizeof(A) / sizeof(A[0]);
	Solution1 s;
	int num = s.firstMissingPositive(A, len);
	cout << "num= " << num << endl;
}
2.数组:除了二个数出现一次,其他数都出现二次
void test02(int *a,int n) {
	int con = 0;
	for (int i = 0; i < n; ++i) {
		con ^= a[i];
	}
	int mask = 1;
	for (; (con&mask) == 0; mask <<= 1);
	int x = 0;
	int y = 0;
	for (int i = 0; i < n; ++i) {
		if (a[i] & mask)
			x ^= a[i];
		else
			y ^= a[i];
	}
	cout << "x = " << x << endl;
	cout << "y = " << y << endl;
}
3.Leetcode84 给出一个直方图,求最大面积矩形。
class Solutin2 {
public:
	int largestRectangleArea(vector<int> &height) {
		int n = height.size(), result = 0;
		stack<int> s;
		for (int i = 0; i < n; ++i) {
			while ((!s.empty()) && (height[s.top()] >= height[i])) {
				int h = height[s.top()];
				s.pop();
				result = max(result, (i - 1 - (s.empty() ? (-1) : s.top()))*h);
			}
			s.push(i);
		}
		while (!s.empty()) {
			int h = height[s.top()];
			s.pop();
			result = max(result, (n - 1 - (s.empty() ? (-1) : s.top()))*h);
		}
		return result;
	}
};

void test03() {
	Solutin2 s;
	vector<int>  vec = { 2,1,5,6,2,3,0 };
	int result = s.largestRectangleArea(vec);
	cout << "result = " << result << endl;
}
4.滑动窗口的最大值(数组上一个为k的滑动窗口的最大值求解) :运用了双端队列
void MaxNum(vector<int> &vec,vector<int> &b,int k){
	deque<int> deq;
	for (int i = 0; i < vec.size(); ++i) {
		while (!deq.empty() && deq.front() <= i - k)
			deq.pop_front();  //过期了扔掉
		while (!deq.empty() && vec[deq.back()] <= vec[i])
			deq.pop_back();   //太小了扔掉
		deq.push_back(i);     //注意:入队的是下标
		b[i] = vec[deq.front()];  //队头永远是最大的值
	}
}
void test04() {
	vector<int> vec = { 5,1,3,4,2,6 };
	vector<int> b;
	b.resize(vec.size());
	MaxNum(vec, b, 3);
	int i = 0;
	for (vector<int>::iterator it = b.begin(); it != b.end(); ++it) {
		cout << i++ << ":" << *it << endl;
	}
	auto Max = max_element(b.begin(), b.end());
	cout << "Max = " << *Max << endl; 
	cout << endl;
}
5.链表是否有环,环的入口返回
struct ListNode {
	int val;
	ListNode *next;
	ListNode(int x):val(x),next(nullptr){}
};
class Solution3 { 
public:
	ListNode *detectCycle(ListNode *head) {
		ListNode *p1 = head, *p2 = head;
		do {
			if ((p2 == nullptr) || (p2->next == nullptr))
				return nullptr;
			p2 = p2->next->next;
			p1 = p1->next;
		} while (p1 != p2);
		for (p1 = head; p1 != p2; p1 = p1->next, p2 = p2->next)
			;
		return p1;
	}
};
6.Leetcode138题:一个单链表除了next指针外还有一个random指针随机只想一个元素(可能为空),复制这个单链表
struct RandomListNode {
	int label;
	RandomListNode *next, *random;
	RandomListNode(int x):label(x),next(nullptr),random(nullptr){}
};
class Soulution4 {
public:
	RandomListNode* copyRandomList(RandomListNode *head) {
		if (head == nullptr)
			return nullptr;
		for (RandomListNode *now = head; now;) { //每个节点拷贝一个副本
			RandomListNode *copy = new RandomListNode(now->label);
			copy->next = now->next;
			now->next = copy;
			now = copy->next;
		}
		for (RandomListNode *now = head; now; now = now->next->next) { //random节点拷贝副本
			now->next->random = (now->random == nullptr) ? nullptr : now->random->next;
		}
		RandomListNode *h = head->next, *t = h, *tail = head;
		for (;;) {  //将新旧链表分割开来
			tail = tail->next = t->next;
			if (tail == nullptr) {
				break;
			}
			t = t->next = tail->next;
		}
		return h;
	}
};
7.Leetcode86题:链表partition,链表存放整数,给定x,把比x小的节点放到>=x之前
class Solution5 {
public:
	ListNode* partition(ListNode* head, int x) {
		//分割链表,val值小于x的节点重构的链表头节点为h1,反之为h2
		ListNode* h1 = nullptr, *t1 = nullptr, *h2 = nullptr, *t2 = nullptr;
		for (; head; head = head->next) {
			if (head->val < x) {
				if (t1) {
					t1 = t1->next = head;
				}
				else {
					h1 = t1 = head;
				}
			}
			else if (t2) {
				t2 = t2->next = head;
			}
			else {
				h2 = t2 = head;
			}
		}
		if (t2) {
			t2->next = nullptr;
		}
		if (t1) {
			t1->next = h2;
		}
		return h1 ? h1 : h2;
	}
};
8.random_shuffle的底层实现,随机产生一个全排列
void Random_shuffle(int *arr,int len) {
	for (int i = 0; i < len; ++i) {
		swap(arr[i], arr[rand() % (len - i) + i]);
	}
}
9.Leetcode11题:一个数组a[i]表示数轴上i的位置有一条高度为a[i]的竖直的线段,把两条线段当作一个容器左右边的高度,问那两条线段组成的容器容积最大?
class Solution6 {
public:
	int maxArea(vector<int>& height) {
		int best = 0;
		int n = height.size();
		for (int i = 0, j = n - 1; i < j;) {
			best = max(best, min(height[i], height[j])*(j - i));
			if (height[i] < height[j])
				++i;
			else
				--j;
		}
		return best;
	}
};
10.给定数组a,求下标对i, j满足a[i] ≤ a[j],并且j – i最大。
int run(vector<int> &a) {
	int n = a.size();
	vector<int> p(n);   //记录前缀最小值
	for (int i = 0; i < n; ++i) {
		p[i] = ((i == 0) || (a[i] < p[i - 1])) ? a[i] : p[i - 1];
	}
	int best = 0;
	for (int j = n - 1; j > best; --j) {
		while ((j > best) && (a[j] >= p[j - best - 1]))
			++best;
	}
	return best;
}
11.给定n * n的01方阵,每一行都是降序的(即先连续的一段1,再连续的一段0),求1最多的那行中1的个数
int oneofnumbers(vector<vector<char>> &a) {
	int n = a.size();
	int best = 0;
	for (int i = 0; (best < n) && (i < n); ++i) {
		while ((best < n) && (a[i][best] == '1'))
			++best;
	}
	return best;
}
12.Leetcode31题:(C++ STL) Next Permutation 找到字典序里的下一个排列。 12345的下一个是12354,而54321的下一个认为是12345
class Soultion7 {
public:
	//算法(二找、一交换、一翻转)
	void nextPermutation(vector<int> &nums) {
		int n = nums.size();
		int x;
		for (x = n - 2; (x >= 0) && (nums[x] >= nums[x + 1]); --x)
			;
		if (x < 0) {
			reverse(nums.begin(), nums.end());
			return;
		}
		int y;
		for (y = n - 1; nums[y] <= nums[x]; --y)
			;
		swap(nums[x], nums[y]);
		reverse(nums.begin() + x + 1, nums.end());
	}
};

void test05() {
	vector<int> vec = { 1,2,3,4,5 };
	Soultion7 s;
	s.nextPermutation(vec);
	for (auto res : vec) {
		cout << res << " ";
	}
	cout << endl;
}
13.(codility)给定一个数组A和整数K,问有多少对下标i <= j满足max(A[i…j]) – min(A[i…j]) <= K
//滑动窗口
//用两个单调队列:一个最大值,一个最小值
int solution(vector<int> &A, int K) {
	deque<int> qmin, qmax;
	int answer = 0;
	for (int i = 0, j = 0; i < A.size(); ++i) {
		while (j < A.size()) {
			while ((!qmin.empty()) && (A[qmin.back()] >= A[j]))
				qmin.pop_back();
			qmin.push_back(j);
			while ((!qmax.empty()) && (A[qmax.back()] <= A[j]))
				qmax.pop_back();
			qmax.push_back(j);
			if (A[qmax.front()] - A[qmin.front()] <= K)
				++j;
			else
				break;
		}
		if (qmin.front() == i)
			qmin.pop_front();   //到期出队
		if (qmax.front() == i)
			qmax.pop_front();
		answer += j - i;
		if (answer >= INT_MAX)  //题目要求,无关紧要防止溢出
			return INT_MAX;
	}
	return answer;
}
14.绝对众数(一定要超过数组中一半的数)的巧妙实现:
//思路:不相同的两数删除不会改变众数
int MoreOfNumbers(vector<int> &vec) {
	int len = vec.size();
	int count = 0;
	int m = vec[0];
	for (int i = 0; i < len; ++i) {
		if (count == 0) {
			m = vec[i];
			count++;
		}
		else if (m != vec[i]) {
			count--;
		}
		else {
			count++;
		}
	}
	int con = 0;
	for (auto res : vec) {
		if (res == m) {
			con++;
		}
	}
	if (con > len / 2)  //如果确定数组有绝对众数就不用判断
		return m;
	return -1;
}

void testMoreOfNumbers() {
	vector<int> vec = { 1,2,3,4,7,6,7,1,7,2,7,7,7,7,7};
	int res = MoreOfNumbers(vec);
	cout << "众数:" << res << endl;
}
15.简单练习:翻转数组简化法
void ReverseArr() {
	int arr[] = { 1,2,8,7,4,5 };
	int len = sizeof(arr) / sizeof(int);
	for (int i = 0, j = len - 1; i < j; swap(arr[i++], arr[j--]));
	for (auto res : arr)
		cout << res << " ";
	cout << endl;
}
16.单链表整体逆置
struct ListNode {
	int val;
	ListNode *next;
	ListNode(int x):val(x),next(nullptr){}
};
void ReverseList(ListNode* pHead) {
	if (nullptr == pHead || nullptr == pHead->next)
		return;
	ListNode* pCur = pHead->next;
	ListNode* pPre = pCur;
	pCur = pCur->next;
	ListNode* pNext = nullptr;
	while (pCur) {
		pNext = pCur->next;
		pCur->next = pHead->next;
		pHead->next = pCur;
		pPre->next = pNext;
		pCur = pNext;
	}
}
17.单链表局部逆置
void ReversePartList(ListNode* pHead, int from, int to) {
	ListNode* pCur = pHead->next;
	int i = 0;
	for (i = 0; i < from - 1; ++i) {
		pHead = pCur;
		pCur = pCur->next;
	}
	ListNode* pPre = pCur;
	pCur = pCur->next;
	ListNode* pNext = nullptr;
	for (; i < to-1; ++i) {
		pNext = pCur->next; //先记录当前值的后一个元素
		pCur->next = pHead->next; //当前值移动到局部最前方
		pHead->next = pCur;  //更改局部最前部的前一个元素指向当前元素
		pPre->next = pNext;  //保证局部链尾部与原链连接
		pCur = pNext;        //更新当前值为下一个准备移动的元素
	}
}
18.单链表销毁
void DestroyList(ListNode** pHead) { 
	//链表销毁
	if (*pHead == nullptr) {
		cout << "无法析构,链表为空!" << endl;
		return;
	}
	ListNode* temp = *pHead;
	ListNode* pnext = nullptr;
	while (temp) {
		pnext = temp->next;
		delete temp;
		temp = pnext;
	}
	*pHead = nullptr;
	cout << "析构链表结束" << endl;
}
19.打印单链表
void PrintList(ListNode* phead) {
	//打印链表
	ListNode *temp = phead->next;
	while (temp) {
		cout << temp->val << " ";
		temp = temp->next;
	}
	cout << endl;
}
16-19的测试:
void testReverseList() {
	//测试链表用例
	ListNode *pHead = new ListNode(0);
	ListNode *ppHead = pHead;
	for (int i = 0; i < 5; ++i) {
		ListNode *p = new ListNode(i + 1);
		ppHead->next = p;
		ppHead = p;
	}
	cout << "逆序链表前:" << endl;
	PrintList(pHead);
	ReverseList(pHead);
	cout << "逆序链表后:" << endl;
	PrintList(pHead);
	cout << "逆序局部链表:" << endl;
	ReversePartList(pHead, 3, 5);
	PrintList(pHead);
	DestroyList(&pHead);
	DestroyList(&pHead);
}
20.推荐一些练习题和算法学习:
  • 数 1-100,缺少两个数,求这两个数?位运算?解方程?
  • Leetcode137 除了一个数出现一次外,其他所有数都出现3次,求那个数
  • Leetcode160题:两个单向链表找交点
  • 最大子数组和
  • 最大直方图(单调堆栈)
  • 滑动窗口最大值(单调队列)
  • 快排Partition过程
  • 杨氏矩阵查找:荷兰国旗问题、First Missing Positive
  • 排列组合相关:Next/Previous permutation
  • 树相关:二叉树遍历、(最大、最小)深度、同构、镜像判断、平衡判断
  • KMP学习
  • Manacher
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值