剑指2题目汇总(一)

1.赋值运算符重载

  • 赋值运算符函数的参数为const引用类型;----->若类型为类,会产生临时对象,调用复制构造函数。
  • 赋值运算符函数的返回值为引用类型;----->若类型为类,则连续赋值语句编译不通过(类型不匹配)、会产生临时对象,调用复制构造函数。
  • 检查赋值的对象是否和this是同一个;----->
  • 赋值的对象和this不是同以对象,则需要先释放原有对象;----->以防内存泄漏
//==================================================================
// author:pb
// date:2019-06-04
//==================================================================
#include "pch.h"
#include <iostream>
class CData {
public:
	
	CData(const char* data);
	CData(const CData& data);
	CData&  operator =(const CData& data);
	char* GetData();
	~CData();
private:
	char* m_data;
};
CData::CData(const char* data = nullptr)
{
	std::cout << "this is construction function" << std::endl;
	if (data == nullptr)
	{
		m_data = new char[1];
		*m_data = '\0';
	}
	else
	{
		m_data = new char[strlen(data) + 1];
		strcpy(m_data, data);
	}
		
}
CData::~CData()
{
	
	delete[] m_data;
}
CData::CData(const CData& data)
{
	std::cout << "this is copy constructor function" << std::endl;
	m_data = new char[strlen(data.m_data) + 1];
	strcpy(m_data, data.m_data);
}
CData&  CData::operator =(const CData& data)
{
	std::cout << "this is assignment operator function" << std::endl;
	if (&data == this)
		return *this;
	delete[] m_data;
	m_data = nullptr;
	m_data = new char[strlen(data.m_data) + 1];
	strcpy(m_data, data.m_data);
	return *this;
}
char* CData::GetData()
{
	return m_data;
}
void test1()
{
	const char* str = "you are a nice man!";
	CData d1(str);
	std::cout << "test1 d1.m_data:" << d1.GetData() << std::endl;
	CData d2 = d1;//调用复制构造函数
	std::cout << "test1 d2.m_data:" << d2.GetData() << std::endl;
	CData d3;
	d3 = d1;//调用运输算符重载函数
	std::cout << "test1 d3.m_data:" << d3.GetData() << std::endl;
	d3 = d3;
	d1 = d2 = d3;
}
int main()
{
	test1();
	getchar();
}

2.单例模式实现(Singleton)

  • 构造函数为private或protected(即不能实例化)
  • Instance的类型为静态的CSingleton
  • _instance指针为static
//==================================================================
// author:pb
// date:2019-06-05
//==================================================================
#include "stdafx.h"
class CSingleton {
public:
	int m_data;
public:
	static CSingleton* Instance()
	{
		return _instance;
	}
private:
	CSingleton() {};//必须有函数体
	static CSingleton* _instance;
};
CSingleton* CSingleton::_instance = new CSingleton();
int main()
{
	CSingleton *sg = CSingleton::Instance();
	sg->m_data = 10;

    return 0;
}

3.数组中重复的数字

题目一:找出数组中重复的数字(数字范围0~n-1),如{2,3,1,0,2,5,3}则输出2,3

思路一:排序再遍历,时间复杂度为O(nlogn)

思路二:哈希表,时间复杂度为O(n),空间复杂度为O(n)

思路三:交换

bool duplicate(int numbers[], int length, int* duplication)
{
	if (numbers == nullptr || length <= 0)
		return false;
	for (int i = 0; i < length; ++i)
	{
		if (numbers[i] < 0 || numbers[i] > length-1)
			return false;
	}
	int *tmp_arr = new int[length]();//1.new,每个元素都初始化为0
	for (int i = 0; i < length; ++i)
	{
		tmp_arr[numbers[i]]++;
	}

	if (tmp_arr[*duplication] > 1)
	{
		delete[] tmp_arr;
		return true;
	}	
	else
	{
		delete[] tmp_arr;
		return false;
	}

}

题目一:找出数组中重复的数字(数字范围0~n,数组长度为n+1,即至少有一个数字重复),要求不能改变原有数组

思路:利用二分查找的思想,时间复杂度O(nlogn)

4.二维数组查找

题目:二维数组如下从向右、向下递增,判断某值在不在该二维数组

思路一:遍历,时间复杂度为O(n*m)

思路二:首先选取右上角的数字和目标值比较,如果目标值小于右上角的值(图中的9),就剔除该列,依次右上角(图中的8)比较,直到小于目标值时,停止列比较,换行比较,选左上角(图中的1),往下依次剔除。

5.替换字符串中的空格

题目:字符串中的空格替换为“%20”,如“We are harry.”---->"We%20are%20harry."

思路一:遍历,1个字符替换成3个字符,需要移动后面的字符串,时间复杂度O(n2)

思路一:先遍历一遍,计算出空格的个数,从而计算出替换后字符串的总长度,然后用双指针,从后往前,依次填充、移动,时间复杂度为O(n)

6.从尾到头打印单链表

思路一:翻转链表,再打印,但是会改变结构

思路二:使用栈

思路三:使递归(和栈同样的思想),但递归的方法会有栈溢出的风险(链表过长的话)

void PrintReversedOrder(ListNode* head)
{
	std::stack<int> slist;
	while (nullptr != head)
	{
		slist.push(head->val);
		head = head->next;
	}
	while (!slist.empty())
	{
		std::cout << slist.top() << " ";
		slist.pop();
	}
	std::cout << "\n";
}
void PrintReversedOrderByRecurisive(ListNode* head)
{
	if (nullptr == head)
		return;
	PrintReversedOrderByRecurisive(head->next);
	std::cout << head->val << " ";
}

7.重建二叉树

题目:根据前序、中序的结果来构建二叉树,输出根节点(数字不重复),如前序{1,2,4,7,3,5,6,8},中序{4,7,2,1,5,3,8,6},返回该二叉树的根节点

思路:根据前序的第一个节点为根节点的特性(例子中的数字1),再从中序中找出该数字的位置,则该位置的前面都为左子树的部分(4,7,2),该节点的后面都为右子树的部分(5,3,8,6);然后是递归的调用。

// 007_ConstructBinaryTree.cpp: 定义控制台应用程序的入口点。
//==================================================================
// author:pb
// date:2019-06-06
//==================================================================

#include "stdafx.h"
#include<vector>
#include<iostream>
struct TreeNode {
	int val;
	TreeNode* left;
	TreeNode* right;
	TreeNode(int x) :val(x), left(nullptr), right(nullptr) {}
};
TreeNode* _Construct(std::vector<int> &preOrder,
					int preStart, 
					int preEnd,
					std::vector<int> &inOrder, 
					int inStart,
					int inEnd)
{
	TreeNode* root = new TreeNode(preOrder[preStart]);
	if (preStart == preEnd) return root;
	int partion = preStart;
	for (int i = inStart; i <= inEnd; ++i)
	{
		if (inOrder[i] == preOrder[preStart])
		{
			partion = i;
			break;
		}
	}
	std::cout << "preStart=" << preStart << " preEnd=" << preEnd << " inStart=" << inStart << " inEnd=" << inEnd << " partion="<< partion <<std::endl;
	int len = partion - inStart;
	//if (preStart < preEnd && partion > inStart)
	if(len > 0)
	{
		//root->left =_Construct(preOrder, preStart+1, partion, inOrder, inStart, partion-1);
		root->left = _Construct(preOrder, preStart + 1, preStart+len, inOrder, inStart, partion - 1);
	}
	//if (inStart < inEnd && partion < inEnd)
	if(len < preEnd - preStart)
	{
		//root->right = _Construct(preOrder, partion + 1, preEnd, inOrder, partion + 1, inEnd);
		root->right = _Construct(preOrder, preStart + len + 1, preEnd, inOrder, partion + 1, inEnd);
	}
	return root;
}
TreeNode* Construct(std::vector<int> &preOrder, std::vector<int> &inOrder)
{
	if (preOrder.size() <= 0 || inOrder.size() <= 0)
		return nullptr;

	return _Construct(preOrder, 0, preOrder.size() - 1, inOrder, 0, inOrder.size()-1);
}
void Test()
{
	std::vector<int> preOrder{ 1, 2, 4, 7, 3, 5, 6, 8 };
	std::vector<int>  inOrder{ 4, 7, 2, 1, 5, 3, 8, 6 };
	TreeNode* root = Construct(preOrder, inOrder);

}
int main()
{
	Test();
	getchar();
    return 0;
}

 

8.二叉树的下一个节点

题目:给出二叉树和一个节点,找出中序遍历的下一个节点

 

9.用两个栈实现一个队列

注意:注意实现队列的入队、出队,用第一个栈s1入队,出队的时候从第二个栈s2弹出,关键一点是:出队是检测s2是否为空,若为空要把s1的元素以此弹出,压入s2,然后s2栈顶的元素为要出队的元素。

另:怎么用两个队列实现一个栈?

// 009_QueueWithTwoStack.cpp: 定义控制台应用程序的入口点。
//==================================================================
// author:pb
// date:2019-06-06
//==================================================================
#include "stdafx.h"
#include<stack>
#include<queue>
#include<assert.h>

template<typename T>
class squeue {
public:
	squeue() {}
	~squeue() {}
	void spush(T &val)
	{
		s1.push(val);
	}

	T sfront()
	{
		if (s2.empty())
		{
			while (!s1.empty())
			{
				s2.push(s1.top());
				s1.pop();
			}
		}
		assert(!s2.empty());
		return s2.top();
	}
	void spop()
	{
		if (s2.empty())
		{
			while (!s1.empty())
			{
				s2.push(s1.top());
				s1.pop();
			}
		}
		assert(!s2.empty());
		return s2.pop();
	}
private:
	std::stack<T> s1;
	std::stack<T> s2;
};
void Test1()
{
	squeue<int> sq;
	int a = 1;
	int b = 2;
	int c = 3;
	sq.spush(a);
	sq.spush(b);
	sq.spush(c);
	//sq.spop();
	int ret = sq.sfront();
}
void Test2()
{
	squeue<char> sq;
	char a = 'a';
	char b = 'b';
	char c = 'c';
	sq.spush(a);
	sq.spush(b);
	sq.spush(c);
	sq.spop();
	char ret = sq.sfront();
}
int main()
{
	Test1();
	Test2();
    return 0;
}

10.斐波那契数列

// 010_Fibonacci.cpp: 定义控制台应用程序的入口点。
//==================================================================
// author:pb
// date:2019-06-06
//==================================================================

#include "stdafx.h"
#include<iostream>
//递归
int Fibonacci(int n)
{
	if (n <= 1)
		return n;
	return Fibonacci(n - 1) + Fibonacci(n - 2);
}
//非递归
int Fibonacci1(int n)
{
	if (n <= 1)
		return n;
	int last_one = 1;
	int last_two = 0;
	int ret = 0;
	for (int i = 2; i <= n; ++i)
	{
		ret = last_one + last_two;
		last_two = last_one;
		last_one = ret;	 
	}
	return ret;
}
int main()
{
	std::cout<< "Fibonacci(" << 10 << ")=" << Fibonacci(10) << std::endl;
	std::cout << "Fibonacci1(" << 10 << ")=" << Fibonacci1(10) << std::endl;
	std::cout << "Fibonacci1(" << 100 << ")=" << Fibonacci1(40) << std::endl;
	std::cout << "Fibonacci(" << 100 << ")=" << Fibonacci(40) << std::endl;
	
	getchar();
    return 0;
}

 

11.旋转数组的最小值

题目:给出一个递增旋转过的数组,输出数组的最小值,如数组{3,4,5,1,2},最小值为1

思路一:遍历一遍,时间复杂度为O(n),不是本题所考察的点。

思路二:二分查找的思想

 

12.矩阵中的路径

13.机器人的运动范围

14.剪绳子

15.二进制中1的个数

思路一:按位右移,然后和1按位与。但遇到负数就会死循环

思路二:使用tmp=1和n按位与,然后按位左移,循环操作,直到tmp左移溢出变为0为止。

// 015_BinaryBit.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//==================================================================
// author:pb
// date:2019-06-06
//==================================================================

#include "pch.h"
#include <iostream>
int BinaryBit(int n)
{
	int cnt = 0;
	unsigned int tmp = 1;
	while (tmp)
	{
		if (n & tmp)
			++cnt;
		tmp <<= 1;
	}
	return cnt;
}
void Test()
{
	int ret = BinaryBit(1);
	ret = BinaryBit(3);
	ret = BinaryBit(0xFF88);
	ret = BinaryBit(0x9999);
}
int main()
{
	Test();
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值