剑指offer

变态跳台阶

题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

class Solution {
public:
    int jumpFloorII(int number) {
        vector<int>cur(number + 1, 0);
		vector<vector<int> > dp(number + 1, cur);
		int sum = 0;
		for (int i = 1; i <=number; i++)
		{
			dp[1][i] = 1;
		}

		for (int time = 2; time <= number; time++) {
			for (int step = time; step <= number; step++) {
				if (time == step)
					dp[time][step] = dp[time - 1][step - 1];
				else {
					dp[time][step] = dp[time - 1][step - 1] + dp[time][step - 1];
				}

			}

		}
		for (int i = 1; i <= number; i++) {
			sum += dp[i][number];
		}
		return sum;
    }
};

矩形覆盖

题目描述

我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

#include<iostream>
using namespace std;
class Solution {
public:
	int rectCover(int number) {
		if (number == 0)
			return 0;
		if (number == 1)
			return 1;
		else if (number == 2) {
			return 2;
		}
		/*else
			return rectCover(number - 1) + rectCover(number - 2);*/

		int k = 2, a = 1, b = 2, res;
		while (k < number) {

			res = a + b;
			a = b;
			b = res;
			k++;

		}
		return res;

	}
};

int main() {

	Solution *sol = new Solution();
	cout << sol->rectCover(3);

	std::cin.get();
	return 0;
}

可以先横着放,也可以先竖着放

二进制中1的个数

题目描述

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

#include<iostream>
#include<string>
#include<bitset>
using namespace std;


class Solution {
public:

    int  NumberOf1(int n) {
	    return bitset<32>(n).count();
    }

};

bitset用法:

https://www.cnblogs.com/magisk/p/8809922.html

    bitset<8> foo ("10011011");

    cout << foo.count() << endl;  //5  (count函数用来求bitset中1的位数,foo中共有5个1
    cout << foo.size() << endl;   //8  (size函数用来求bitset的大小,一共有8位

    cout << foo.test(0) << endl;  //true  (test函数用来查下标处的元素是0还是1,并返回false或true,此处foo[0]为1,返回true
    cout << foo.test(2) << endl;  //false  (同理,foo[2]为0,返回false

    cout << foo.any() << endl;  //true  (any函数检查bitset中是否有1
    cout << foo.none() << endl;  //false  (none函数检查bitset中是否没有1
    cout << foo.all() << endl;  //false  (all函数检查bitset中是全部为1

树的子结构 

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<map>
using namespace std;

struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
		val(x), left(NULL), right(NULL) {
	}
};
class Solution {
public:
	bool dfs(TreeNode* pRoot1, TreeNode* pRoot2, bool flag) {
		
		if (pRoot1 != NULL && pRoot2 == NULL)
			return false;
		if (pRoot1 == NULL &&pRoot2!=NULL)
			return false;
		if (pRoot1 == NULL && pRoot2 == NULL)
			return true;

		if (pRoot1->val == pRoot2->val) {
			if (pRoot2->left == NULL && pRoot2->right == NULL)
				return true;

			flag = true;
			if (dfs(pRoot1->left, pRoot2->left, flag) && dfs(pRoot1->right, pRoot2->right, flag))
				return true;
			else {
				flag = false;
				return dfs(pRoot1->left, pRoot2, flag) || dfs(pRoot1->right, pRoot2,flag);
			}
		}
		else {
			if (flag)
				return false;
			else
				return dfs(pRoot1->left, pRoot2, flag) || dfs(pRoot1->right, pRoot2, flag);

		}
	}
	bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
	{
		bool flag = false;
		return dfs(pRoot1, pRoot2, false);

	}
};

二叉树中和为某一值的路径

输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)

class Solution {
public:
	vector<vector<int> >res;

	//bool cmp(const vector<int> &a, const vector<int> &b) {
	//	int as = a.size();
	//	int bs = b.size();
	//	return as > bs;
	//}

	void dfs(TreeNode *root,vector<int> stack,int sum,int expectNumber) {
		if (root == NULL)return;
		stack.push_back(root->val);
		sum += root->val;
		if (sum > expectNumber)
			return;
		else if(root->left ==NULL && root->right==NULL && sum == expectNumber)
		{
			res.push_back(stack);
			return;
		}

		dfs(root->left, stack, sum, expectNumber);
		dfs(root->right, stack, sum, expectNumber);
		sum -= root->val;
		stack.pop_back();
		
	}
	vector<vector<int> > FindPath(TreeNode* root, int expectNumber) {
		
		vector<int> stack;
		int sum = 0;

		dfs(root, stack, sum, expectNumber);

		sort(res.begin(), res.end(), [](const vector<int> &a, const vector<int> &b) {return a.size() > b.size(); });

		return res;
	}
};

最小的K个数 - trick

题目描述

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

最小k个数-->建立大小为k的大根堆

最大k个数-->建立大小为k的小根堆

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>

using namespace std;

class Solution {
public:
	void swap(vector<int> &v, int a, int b) {
		int tmp = v[a];
		v[a] = v[b];
		v[b] = tmp;
	}

	void downAdjust(int i, vector<int> &v, int len) { //建最大堆,遍历v[k]~v[v.size()-1],只要小于堆顶就把堆顶(top[0])替换掉
	
		int largest, left, right;
		while (i < len) {
			largest = i;
			left = 2 * i + 1;
			right = 2 * i + 2;
			if (right >= len && left >= len)break;
			if (left<len && v[left]>v[i]) {
				largest = left;
			}
			if (right<len &&v[right]>v[largest]) {
				largest = right;
			}
			if (largest != i) {
				swap(v, largest, i);
				i = largest;
			}
			else
				break;
		}

	}


	void buildHeap(vector<int> &v) {
		int len = v.size();
		for (int i = len / 2 - 1; i >= 0; i--) {
			downAdjust(i, v, len);
		}
	}

	vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
		vector<int> res;
		int len = input.size();
		if (len == 0 || k > len || k == 0)return res;
		vector<int> top(k, 0);
		for (int i = 0; i < k; i++)
		{
			top[i] = input[i];
		}
		
		buildHeap(top);
		for (int i = k; i < input.size(); i++)
		{
	
			if (input[i] < top[0]) {
				top[0] = input[i];
				downAdjust(0, top, k);

			}
		}
		return top;
	}
};
int main() {

	Solution *sol = new Solution();
	vector<int> input = { 3 };
	vector<int> top = sol->GetLeastNumbers_Solution(input, 0);

	for (int i = 0; i < top.size(); i++)
	{
		cout << top[i] << endl;
	}
	std::cin.get();
	return 0;
}

丑数 - trick

题目描述

把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

超时代码:

class Solution {
public:

	bool judge(int x) {
		//if (x == 1)return true;

		while (x % 2 == 0)
			x /= 2;
		while (x % 3 == 0)
			x /= 3;
		while (x % 5 == 0)
			x /= 5;


		if (x == 1)return true;
		else
			return false;
		

	}

	int GetUglyNumber_Solution(int index) {
		int k = 0;
		int i = 0;
		while (k<index)
		{
			i++;
			if (judge(i)) {
				k++;
			}
			
		}
		return i ;
	}
};

AC代码:
 

class Solution {
public:

	

	int GetUglyNumber_Solution(int index) {
		if (index < 7)return index;
		vector<int>res(index, 0);
		res[0] = 1;
		int t2 = 0, t3 = 0, t5 = 0;
		for (int i = 1; i < index; i++) {

			res[i] = min(res[t2] * 2, min(res[t3] * 3, res[t5] * 5));
			if (res[i] == res[t2] * 2)t2++;
			if (res[i] == res[t3] * 3)t3++;
			if (res[i] == res[t5] * 5)t5++;
		}
		return res[index - 1];
	}
};

 

参考:https://www.nowcoder.com/questionTerminal/6aa9e04fc3794f68acf8778237ba065b 

把数组排成最小的数 - trick

题目描述

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>

using namespace std;
class Solution {
public:
	string PrintMinNumber(vector<int> numbers) {
		vector<string> res;
		for (int i = 0; i < numbers.size(); i++)
		{
			res.push_back(to_string(numbers[i]));
		}
		sort(res.begin(), res.end(), [](string a, string b) {return a + b < b + a; });
		string str;
		for (int i = 0; i < res.size(); i++)
		{
			str += res[i];
		}
		return str;
	}
};
int main() {
	Solution sol;
	vector<int> v = { 3,32,321 };
	cout << sol.PrintMinNumber(v) << endl;

	cin.get();
}

整数中1出现的次数(从1到n整数中1出现的次数)--trick

暴力解法:

class Solution {
public:
	int num1(int x) {
		string str = to_string(x);
		int cnt = 0;
		for (int i = 0; i < str.size(); i++)
		{
			if (str[i] == '1')
				cnt++;
		}
		return cnt;
		
	}
	int NumberOf1Between1AndN_Solution(int n)
	{
		int sum = 0;
		for (int i = 1; i <= n; i++)
		{
			sum += num1(i);
		}
		return sum;
	}
};

找规律:

class Solution {
public:


	int getLenOfNum(int n) {
		int len = 0;
		while (n != 0) {
			len++;
			n /= 10;
		}
		return len;
	}
	int NumberOf1Between1AndN_Solution(int n)
	{

		if (n < 1)
			return 0;
		int len = getLenOfNum(n);
		if (len == 1)
			return 1;
		int tmp = (int)pow(10, len - 1);
		int first = n / tmp;
		int firstOneNum = first == 1 ? n % tmp + 1 : tmp;
		int otherOneNUm = first * (len - 1) * (tmp / 10);
		return firstOneNum + otherOneNUm + NumberOf1Between1AndN_Solution(n % tmp);
	}
};

二叉搜索树与双向链表 -- trick 

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

 通过一个pre指针来记录上一个节点,然后中序遍历

参考代码:https://www.nowcoder.com/questionTerminal/947f6eb80d944a84850b0538bf0ec3a5

链接:https://www.nowcoder.com/questionTerminal/947f6eb80d944a84850b0538bf0ec3a5
来源:牛客网

class Solution {
public:
    TreeNode* Convert(TreeNode* pRootOfTree)
    {
        if(pRootOfTree == nullptr) return nullptr;
        TreeNode* pre = nullptr;
         
        convertHelper(pRootOfTree, pre);
         
        TreeNode* res = pRootOfTree;
        while(res ->left)
            res = res ->left;
        return res;
    }
     
    void convertHelper(TreeNode* cur, TreeNode*& pre)
    {
        if(cur == nullptr) return;
         
        convertHelper(cur ->left, pre);
         
        cur ->left = pre;
        if(pre) pre ->right = cur;
        pre = cur;
         
        convertHelper(cur ->right, pre);
         
         
         
    }
};

 我的代码,记录左右标记

class Solution {
public:

	TreeNode *link(TreeNode *root, bool is_left) {
		if (root == NULL)return root;
		if (root->left == NULL && root->right == NULL) return root;

		root->left = link(root->left, true);
		if (root->left != NULL)
			root->left->right = root;
		root->right = link(root->right, false);
		if (root->right != NULL)
			root->right->left = root;

		TreeNode *cur = root;
		if (!is_left) {
			while (cur->left != NULL) 
				cur = cur->left;		
		}
		else {
			while (cur->right != NULL) 
				cur = cur->right;
		}
		return cur;
	}


	TreeNode* Convert(TreeNode* pRootOfTree)
	{
		bool is_left = true;
		if (pRootOfTree == NULL)return NULL;
		pRootOfTree->left = link(pRootOfTree->left, is_left);
		if (pRootOfTree->left != NULL)
			pRootOfTree->left->right = pRootOfTree;
		pRootOfTree->right = link(pRootOfTree->right, !is_left);
		if (pRootOfTree->right != NULL)
			pRootOfTree->right->left = pRootOfTree;

		while (pRootOfTree->left != NULL) {
			pRootOfTree = pRootOfTree->left;
		}
		return pRootOfTree;
	}
};

按之字形顺序打印二叉树 -- trick

两个stack分别记录奇数层和偶数层

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

class Solution{
public:
	vector<vector<int> > Print(TreeNode* pRoot) {
		vector<vector<int> > res;
		if (!pRoot)return res;

		stack<TreeNode*> s1;
		stack<TreeNode*> s2;

		s1.push(pRoot);
		while (!s1.empty() || !s2.empty()) {
			vector<int>cur;
			while(!s1.empty()) {
				
				TreeNode *w = s1.top();
				cur.push_back(w->val);
				s1.pop();
				if (w->left) {
					s2.push(w->left);
				}
				if (w->right) {
					s2.push(w->right);
				}
			}
			if (!cur.empty()) {
				res.push_back(cur);
				cur.clear();
			}

			while (!s2.empty()) {
				TreeNode *w = s2.top();
				cur.push_back(w->val);
				s2.pop();
				if (w->right) {
					s1.push(w->right);
				}
				if (w->left) {
					s1.push(w->left);
				}
			}
			if (!cur.empty()) {
				res.push_back(cur);
				cur.clear();
			}
		}
		


		return res;
	}

};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值