内容整理自网络,侵权联系删除
1、链表反转
输入:{1,2,3}
返回值:{3,2,1}
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {}
};
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
//A->B->C
ListNode* pre = NULL;//NULL
ListNode* cur = pHead;//A
while (cur != NULL){
ListNode* temp;
temp = cur->next;//B
cur->next = pre;//NULL
pre = cur;//A
cur = temp;//B
}
return pre;
}
};
2、排序
给定一个长度为 n 的数组,请你编写一个函数,返回该数组按升序排序后的结果。
class Solution {
public:
vector<int> MySort(vector<int>& arr) {
for(int i=0;i<arr.size();i++) {
for(int j=i+1;j<arr.size();j++) {
if(arr[i]>arr[j]) {
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
}
return arr;
}
};
3、设计LRU缓存结构
设计LRU(最近最少使用)缓存结构,该结构在构造时确定大小,假设大小为 capacity ,操作次数是 n ,并有如下功能:
- Solution(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存;
- get(key):如果关键字 key 存在于缓存中,则返回key对应的value值,否则返回 -1 ;
- set(key, value):将记录(key, value)插入该结构,如果关键字 key 已经存在,则变更其数据值 value,如果不存在,则向缓存中插入该组 key-value ,如果key-value的数量超过capacity,弹出最久未使用的key-value。
提示:: - 某个key的set或get操作一旦发生,则认为这个key的记录成了最常使用的,然后都会刷新缓存;
- 当缓存的大小超过capacity时,移除最不经常使用的记录;
- 返回的value都以字符串形式表达,如果是set,则会输出"null"来表示(不需要用户返回,系统会自动输出),方便观察
- 函数set和get必须以O(1)的方式运行;
- 为了方便区分缓存里key与value,下面说明的缓存里key用""号包裹 。
输入:[“set”,“set”,“get”,“set”,“get”,“set”,“get”,“get”,“get”],[[1,1],[2,2],[1],[3,3],[2],[4,4],[1],[3],[4]],2
返回值:[“null”,“null”,“1”,“null”,“-1”,“null”,“-1”,“3”,“4”]
说明:
我们将缓存看成一个队列,最后一个参数为2代表capacity,所以
Solution s = new Solution(2);
s.set(1,1); //将(1,1)插入缓存,缓存是{“1”=1},set操作返回"null"
s.set(2,2); //将(2,2)插入缓存,缓存是{“2”=2,“1”=1},set操作返回"null"
output=s.get(1);// 因为get(1)操作,缓存更新,缓存是{“1”=1,“2”=2},get操作返回"1"
s.set(3,3); //将(3,3)插入缓存,缓存容量是2,故去掉某尾的key-value,缓存是{“3”=3,“1”=1},set操作返回"null"
output=s.get(2);// 因为get(2)操作,不存在对应的key,故get操作返回"-1"
s.set(4,4); //将(4,4)插入缓存,缓存容量是2,故去掉某尾的key-value,缓存是{“4”=4,“3”=3},set操作返回"null"
output=s.get(1);// 因为get(1)操作,不存在对应的key,故get操作返回"-1"
output=s.get(3);//因为get(3)操作,缓存更新,缓存是{“3”=3,“4”=4},get操作返回"3"
output=s.get(4);//因为get(4)操作,缓存更新,缓存是{“4”=4,“3”=3},get操作返回"4"
//lambda函数
static const auto io_sync_off = [](){
// turn off sync,关闭输入输出流的缓存
std::ios::sync_with_stdio(false);
// untie in/out streams,实现输入和输出流的解绑
std::cin.tie(nullptr);
return nullptr;
}();
class Solution {
list<pair<int, int>> dlist;//双向链表
unordered_map<int, list<pair<int, int>>::iterator> map;
int cap;
//用链表存,链表头部是最近使用的,尾部是最后使用的,如果要删去,就直接把尾部删去就好
public:
Solution(int capacity){
cap=capacity;
}
//key就变得最常用了
int get(int key) {
if(map.count(key)) {
//把这个放在头部,所以需要个tmp存着,然后删掉这个位置,再放到头部
auto tmp=*map[key];
dlist.erase(map[key]);
dlist.push_front(tmp);//把它放在最前面
map[key]=dlist.begin();
return dlist.front().second;
}
return -1;
}
void set(int key, int value){
//如果存在
if(map.count(key)){
dlist.erase(map[key]);//放在头部
}
else if(cap==dlist.size()){
//先删掉末尾的
auto tmp=dlist.back();
map.erase(tmp.first);
dlist.pop_back();
}
dlist.push_front(pair<int, int>(key, value));
map[key]=dlist.begin();//第一个迭代器
}
};
4、实现二叉树先序,中序和后序遍历
给定一棵二叉树,分别按照二叉树先序,中序和后序打印所有的节点。
要求:空间复杂度 O(n),时间复杂度 O(n)
输入:{1,2,3}
返回值:[[1,2,3],[2,1,3],[2,3,1]]
class Solution {
public:
vector<int> pre, mid, post;
vector<vector<int>> res;
vector<vector<int> > threeOrders(TreeNode* root) {
preorder(root);
inorder(root);
postorder(root);
res.push_back(pre);
res.push_back(mid);
res.push_back(post);
return res;
}
void preorder(TreeNode *root){
if(root == NULL)
return;
pre.push_back(root->val);//根-左-右
preorder(root->left);
preorder(root->right);
}
void inorder(TreeNode *root){
if(root == NULL)
return;
inorder(root->left);//左-根-右
mid.push_back(root->val);
inorder(root->right);
}
void postorder(TreeNode *root){
if(root == NULL)
return;
postorder(root->left);//左-右-根
postorder(root->right);
post.push_back(root->val);
}
//精简版
vector<vector<int> > threeOrders(TreeNode* root) {
if(root==nullptr)
return res={pre,mid,post};
pre.push_back(root->val);
if(root->left!=nullptr)
threeOrders(root->left);
mid.push_back(root->val);
if(root->right!=nullptr)
threeOrders(root->right);
post.push_back(root->val);
return res={pre,mid,post};
}
};
5、最小的K个数
给定一个长度为 n 的可能有重复值的数组,找出其中不去重的最小的 k 个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4(任意顺序皆可)。
要求:空间复杂度 O(n),时间复杂度 O(nlogn)
输入:[4,5,1,6,2,7,3,4],4
返回值:[1,2,4,4]
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k){
vector<int> res;
if(k>input.size())
return res;
multiset<int> s;
for(auto i:input)
s.insert(i);
int i=0;
for(set<int>::iterator it=s.begin();it!=s.end()&&i<k;it++,i++)
res.push_back(*it);
return res;
}
};
6、求二叉树的层序遍历
给定一个二叉树,返回该二叉树层序遍历的结果,(从左到右,一层一层地遍历)
例如:给定的二叉树是{3,9,20,#,#,15,7},
该二叉树层序遍历的结果是[[3],[9,20],[15,7]]
输入:{1,2,3,4,#,#,5}
返回值:[[1],[2,3],[4,5]]
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
static const auto io_sync_off = []{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return nullptr;
}();
class Solution {
public:
vector<vector<int> > levelOrder(TreeNode* root){
queue<TreeNode*> q;
TreeNode* tNode_tmp;
vector<vector<int>> res;
vector<int> vec_tmp;
if(root == nullptr)
return res;
q.push(root);
q.push(NULL);
while(!q.empty()){
tNode_tmp= q.front();
q.pop();
if(tNode_tmp){
vec_tmp.push_back(tNode_tmp->val);
if(tNode_tmp->left)
q.push(tNode_tmp->left);
if(tNode_tmp->right)
q.push(tNode_tmp->right);
}
else{
res.push_back(vec_tmp);
vec_tmp.clear();
if(q.size())
q.push(NULL);
}
}
return res;
}
};
//用队列搞定
7、寻找第K大
有一个整数数组,请你根据快速排序的思路,找出数组中第 k 大的数。给定一个整数数组 a ,同时给定它的大小n和要找的 k ,请返回第 k 大的数(包括重复的元素,不用去重),保证答案存在。
要求:时间复杂度 O(nlogn),空间复杂度 O(1)
输入:[10,10,9,9,8,7,5,6,4,3,4,2],12,3
返回值:9
static const auto io_sync_off = [](){
std::ios::sync_with_stdio(false);
std::cout.tie(nullptr);
std::cin.tie(nullptr);
return nullptr;
}();
class Solution {
public:
int qs(vector<int>& a,int l,int r,int k){
if(l>=r)
return a[l];
int i=l-1,j=r+1,m=a[(l+r)/2];
while(i<j){
do i ++ ;
while (a[i] < m);
do j -- ;
while (a[j] > m);
if(i<j)//a[i] 大于m 大于 a[j]
swap(a[i],a[j]);
}
if(j-l+1>=k)
return qs(a,l,j,k);
else return qs(a,j+1,r,k-(j-l+1));
}
int findKth(vector<int> a, int n, int K){
// write code here
return qs(a,0,n-1,n-K+1);
}
};
8、两数之和
给出一个整型数组 numbers 和一个目标值 target,请在数组中找出两个加起来等于目标值的数的下标,返回的下标按升序排列。(注:返回的数组下标从1开始算起,保证target一定可以由数组里面2个数字相加得到)
要求:空间复杂度 O(n),时间复杂度 O(nlogn)
输入:[3,2,4],6
返回值:[2,3]
说明:因为 2+4=6 ,而 2的下标为2 , 4的下标为3 ,又因为 下标2 < 下标3 ,所以返回[2,3]
class Solution {
public:
/**
* @param numbers int整型vector
* @param target int整型
* @return int整型vector
*/
vector<int> twoSum(vector<int>& numbers, int target){
vector<int> ans;
for (int i = 0 ; i < numbers.size() ; i++){
if (numbers[i] > target) continue;
int temp = target - numbers[i];
for (int j = i + 1; j < numbers.size(); j++){
if (numbers[j] == temp){
ans.push_back(i + 1);
ans.push_back(j + 1);
}
}
}
return ans;
}
};
9、合并两个排序的链表
输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。
要求:空间复杂度 O(1),时间复杂度 O(n)
输入:{-1,2,4},{1,3,4}
返回值:{-1,1,2,3,4,4}
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2){
ListNode* pHead=new ListNode(-1);
ListNode* cur=pHead;
while(pHead1&&pHead2){
if(pHead1->val<=pHead2->val){
cur->next=pHead1;
pHead1=pHead1->next;
}
else{
cur->next=pHead2;
pHead2=pHead2->next;
}
cur=cur->next;
}
cur->next=pHead1?pHead1:pHead2;
return pHead->next;
}
};
10、用两个栈实现队列
用两个栈来实现一个队列,使用n个元素来完成 n 次在队列尾部插入整数(push)和n次在队列头部删除整数(pop)的功能。 队列中的元素为int类型。保证操作合法,即保证pop操作时队列内已有元素。
要求:存储n个元素的空间复杂度为 O(n),插入与删除的时间复杂度都是 O(1)
输入:[“PSH1”,“PSH2”,“POP”,“POP”]
返回值:1,2
说明:
“PSH1”:代表将1插入队列尾部
“PSH2”:代表将2插入队列尾部
"POP“:代表删除一个元素,先进先出=>返回1
"POP“:代表删除一个元素,先进先出=>返回2
class Solution
{
public:
void push(int node){ stack1.push(node); }
int pop(){
if (stack2.empty()){//stack2空了才能继续装
while(!stack1.empty()){
int tmp = stack1.top();
stack1.pop();
stack2.push(tmp);
}
}
int res = stack2.top();
stack2.pop();
return res;
}
private:
stack<int> stack1;
stack<int> stack2;
};
11、跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
要求:时间复杂度:O(n) ,空间复杂度: O(1)
class Solution {
public:
int jumpFloor(int number){
if(number <= 2)
return number;
vector<int>res(number+1, 0);
res[1] = 1;
res[2] = 2;
for(int i = 3; i <= number; i++){
res[i] = res[i-1] + res[i-2];
}//第k级有两种途径,k-1跳1级 加 k-2跳2级
return res[number];
}
};
13、链表中的节点每k个一组翻转
将给出的链表中的节点每 k 个一组翻转,返回翻转后的链表。如果链表中的节点数不是 k 的倍数,将最后剩下的节点保持原样,你不能更改节点中的值,只能更改节点本身。
要求空间复杂度 O(1),时间复杂度 O(n)
例如:给定的链表是 1→2→3→4→5
对于 k=2k = 2k=2 , 你应该返回 2→1→4→3→5
对于 k=3k = 3k=3 , 你应该返回 3→2→1→4→5
输入:{1,2,3,4,5},2
返回值:{2,1,4,3,5}
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
pair<ListNode*, ListNode*> reverseList(ListNode* head, ListNode* tail){
// pre cur next
ListNode* pre = tail->next;
ListNode* cur = head;
while (pre != tail){
ListNode* next = cur->next;
cur->next = pre;
pre = cur;
cur = nex;
}
return { tail, head };
}
ListNode* reverseKGroup(ListNode* head, int k){
// 模拟法,时O(n),空O(1)
ListNode* dummy = new ListNode(0); // 伪头节点
dummy->next = head; // head指向每个组的头节点
ListNode* front = dummy; // 前一个指针初始化为伪头节点
while (head != nullptr){ // 每次往后挪动head指针,不为空则继续
ListNode* tail = front; // 每组的尾指针初始化为组头指针的前一个指针pre
for (int i = 0; i < k; i++) // 判断后续是否还有k个节点
{
tail = tail->next; // 往后移动尾指针k次
if (tail == nullptr) // 若尾指针为空,则说明该组已经不足k个节点
return dummy->next; // 此时满足退出条件,返回伪头节点的下一个节点即可
}
ListNode* back = tail->next; // 每组后一个指针为尾指针的下一个指针
pair<ListNode*, ListNode*> res = reverseList(head, tail);
head = res.first, tail = res.second; // 翻转每组链表后,得到新的头尾指针
// 将翻转后的那组链表重新接回原位置
front->next = head;
tail->next = back;
// 往后移动指针
front = tail;
head = front->next;
}
return dummy->next;
}
};
14、连续子数组的最大和
输入一个长度为n的整型数组array,数组中的一个或连续多个整数组成一个子数组,子数组最小长度为1。求所有子数组的和的最大值。
要求:时间复杂度为 O(n),空间复杂度为 O(n)
进阶:时间复杂度为 O(n,空间复杂度为 O(1)
static const auto io_sync_off = []()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
return nullptr;
}();
class Solution {
public:
int FindGreatestSumOfSubArray(vector<int> array)
{
int len=array.size();
int mx=-2e8;
int now=0;
for(int i=0;i<len;i++)
{
now+=array[i];
mx=max(mx,now);
if(now<0)
now=0;
}
return mx;
}
};
15、最长无重复子数组
给定一个长度为n的数组arr,返回arr的最长无重复元素子数组的长度,无重复指的是所有数字都不相同。子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组
输入:[2,2,3,4,3]
返回值:3
说明:[2,3,4]是最长子数组
static const auto io_sync_off=[]()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
return nullptr;
}();
class Solution {
public:
int maxLength(vector<int>& arr)
{
if(arr.size()<2)
return arr.size();
vector<int>v(100000);
int res=0;
int left=0;
int right=0;
while(right<arr.size())
{
if(v[arr[right]]==0)
{
v[arr[right]]=1;
res=max(res,right-left+1);
right++;
}
else
{
v[arr[left]]=0;
left++;
}
}
return res;
}
};
16、判断链表中是否有环
判断给定的链表中是否有环。如果有环则返回true,否则返回false。
输入分为两部分,第一部分为链表,第二部分代表是否有环,然后将组成的head头结点传入到函数里面。-1代表无环,其它的数字代表有环,这些参数解释仅仅是为了方便读者自测调试。实际在编程时读入的是链表的头节点。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head)
{
if(head==NULL)
return false;
ListNode *fast=head;
ListNode *slow=head;
while (fast!=NULL && fast->next!=NULL)
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast)
return true;
}
}
return false;
}
};
17、合并两个有序的数组
给出一个有序的整数数组 A 和有序的整数数组 B ,请将数组 B 合并到数组 A 中,变成一个有序的升序数组。
注意:
1.保证 A 数组有足够的空间存放 B 数组的元素, A 和 B 中初始的元素数目分别为 m 和 n,A的数组空间大小为 m+n
2.不要返回合并的数组,将数组 B 的数据合并到 A 里面就好了,且后台会自动将合并后的数组 A 的内容打印出来,所以也不需要自己打印
3. A 数组在[0,m-1]的范围也是有序的
输入:[4,5,6],[1,2,3]
返回值:[1,2,3,4,5,6]
说明:A数组为[4,5,6],B数组为[1,2,3],后台程序会预先将A扩容为[4,5,6,0,0,0],B还是为[1,2,3],m=3,n=3,传入到函数merge里面,然后请同学完成merge函数,将B的数据合并A里面,最后后台程序输出A数组。
class Solution {
public:
void merge(int A[], int m, int B[], int n) {
int i = m - 1;
int j = n - 1;
int end = m + n - 1;
while(i >= 0 && j >= 0)
{
A[end--] = A[i] > B[j] ? A[i--] : B[j--];
}
while(i >= 0)
A[end--] = A[i--];
while(j >= 0)
A[end--] = B[j--];
}
};
18、链表中环的入口结点
给一个长度为n链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。
要求:空间复杂度 O(1),时间复杂度 O(n)
例如,输入{1,2},{3,4,5}时,对应的环形链表如下图所示:
输入描述:输入分为2段,第一段是入环前的链表部分,第二段是链表环的部分,后台会根据第二段是否为空将这两段组装成一个无环或者有环单链表
返回值描述:返回链表的环的入口结点即可,我们后台程序会打印这个结点对应的结点值;若没有,则返回对应编程语言的空结点即可。
输入:{1,2},{3,4,5}
返回值:3
说明:返回环形链表入口结点,我们后台程序会打印该环形链表入口结点对应的结点值,即3。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if(!pHead) return nullptr;
ListNode* slow = pHead;
ListNode* fast = pHead;
int i = 0;
while(slow != fast || i == 0)
{
slow = slow->next;
if(!slow) return nullptr;
fast = fast->next;
if(!fast) return nullptr;
fast = fast->next;
if(!fast) return nullptr;
i++;
}
slow = pHead;
while(slow != fast)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
};
19、有效括号序列
给出一个仅包含字符’(‘,’)‘,’{‘,’}‘,’[‘和’]',的字符串,判断给出的字符串是否是合法的括号序列,括号必须以正确的顺序关闭,“()“和”()[]{}“都是合法的括号序列,但”(]“和”([)]“不合法。
要求:空间复杂度 O(n),时间复杂度 O(n)
输入:”([)]”
返回值:false
class Solution {
public:
bool isValid(string s)
{
// write code here
stack<char> st;
int n = s.size();
for(int i=0;i<n;i++){
if(!st.empty() && ((s[i] == ']' && st.top()=='[') || (s[i] == '}' && st.top()=='{')|| (s[i] == ')' && st.top()=='(')))
st.pop();
else
st.push(s[i]);
}
return st.empty();
}
};
20、删除链表的倒数第n个节点
给定一个链表,删除链表的倒数第 n 个节点并返回链表的头指针
例如,给出的链表为: 1→2→3→4→51\to 2\to 3\to 4\to 51→2→3→4→5, n=2n= 2n=2.
删除了链表的倒数第 nnn 个节点之后,链表变为1→2→3→51\to 2\to 3\to 51→2→3→5.
要求:空间复杂度 O(1),时间复杂度 O(n)
输入:{1,2},2
返回值:{2}
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n)
{
if(head == NULL)
return head;
ListNode* dummy = new ListNode(0);
dummy->next = head;
head = dummy;
ListNode* slow = head;
ListNode* fast = head;
for(int i = 0; i <n; i++)
{
fast = fast ->next;
}
while(fast->next != NULL)
{
fast = fast->next;
slow = slow->next;
}
ListNode* temp = slow->next;
slow ->next = slow->next->next;
delete temp;
return dummy->next;
}
};
21、大数加法
以字符串的形式读入两个数字,编写一个函数计算它们的和,以字符串形式返回。
字符串仅由’0’~‘9’构成。要求:时间复杂度 O(n)O(n)O(n)
输入:“1”,“99”
返回值:“100”
说明:1+99=100
static const auto io_sync_off = []()//lambda函数
{
// turn off sync,关闭输入输出流的缓存
std::ios::sync_with_stdio(false);
// untie in/out streams,实现输入和输出流的解绑
std::cin.tie(nullptr);
return nullptr;
}();
class Solution {
public:
string solve(string s, string t)
{
// write code here
int l = s.length();
int r = t.length();
if(!l) return t;
if(!r) return s;
int carry = 0,tmp = 0;
if(l<r)
{
for(int n=r-l;n>0;n--)
s = '0'+s;
l=r;
}
else if(l>r)
{
for(int n=l-r;n>0;n--)
t = '0'+t;
l=r;
}
for(int i=s.size()-1;i>=0;i--)
{
tmp = s[i]-'0'+t[i]-'0'+carry;
if(tmp>=10)
{
carry = 1;
tmp -= 10;
}
else
carry = 0;
s[i] = tmp+'0';
}
if(carry)
s = '1'+s;
return s;
}
};
22、按之字形顺序打印二叉树
给定一个二叉树,返回该二叉树的之字形层序遍历,(第一层从左向右,下一层从右向左,一直这样交替)
该二叉树之字形层序遍历的结果是 [[1],[3,2],[4,5]]
输入:{8,6,10,5,7,9,11}
返回值:[[8],[10,6],[5,7,9,11]]
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {}
};
*/
class Solution {
public:
vector<vector<int> > Print(TreeNode* pRoot)
{
vector<vector<int>> res;
if (!pRoot) return res;
stack<TreeNode*> stk;
queue<TreeNode*> qu;
qu.push(pRoot);
int left = 1;
while (!qu.empty())
{
vector<int> tmp;
int n = qu.size(); // 在循环里面qu.size()会变
for (int i = 0; i < n; i++)
{
TreeNode* node = qu.front();
qu.pop();
tmp.push_back(node->val);
if (left)
{
if (node->left) stk.push(node->left);
if (node->right) stk.push(node->right);
}
else
{
if (node->right) stk.push(node->right);
if (node->left) stk.push(node->left);
}
}
res.push_back(tmp);
left = 1 - left;
while (!stk.empty())
{
qu.push(stk.top());
stk.pop();
}
}
return res;
}
};
23、最长公共子串
给定两个字符串str1和str2,输出两个字符串的最长公共子串
要求: 空间复杂度 O(n^2),时间复杂度 O(n^2)
输入:“1AB2345CD”,“12345EF”
返回值:“2345”
class Solution {
public:
string LCS(string str1, string str2)
{
unordered_map<char, vector<int>> chIndex;
int size1 = str1.size();
int size2 = str2.size();
int maxSize = 0, maxIndex = -1,curIndex,curCount;
int i,j;
for (i = 0; i < size1; i++)
{
chIndex[str1[i]].emplace_back(i);
}
for (i = 0; i < size2; i++)
{
if (chIndex.count(str2[i]) == 0) continue;
for (int x: chIndex[str2[i]])
{
if ( (size1 - x) < maxSize || (size2 - i) < maxSize)
break;
curIndex = i;
curCount = 0;
j = i;
while (str1[x++] == str2[j++])
{
curCount++;
}
if (curCount > maxSize)
{
maxSize = curCount;
maxIndex = curIndex;
}
}
}
return maxSize>0?str2.substr(maxIndex,maxSize):string();
}
};
24、两个链表的第一个公共结点
输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)
要求:空间复杂度 O(1),时间复杂度 O(n)
例如,输入{1,2,3},{4,5},{6,7}时,两个无环的单向链表的结构如下图所示:
输入 分为是3段,第一段是第一个链表的非公共部分,第二段是第二个链表的非公共部分,第三段是第一个链表和第二个链表的公共部分。 后台会将这3个参数组装为两个链表,并将这两个链表对应的头节点传入到函数FindFirstCommonNode里面,用户得到的输入只有pHead1和pHead2。
返回 传入的pHead1和pHead2的第一个公共结点,后台会打印以该节点为头节点的链表
输入:{1,2,3},{4,5},{6,7}
返回值:{6,7}
说明:第一个参数{1,2,3}代表是第一个链表非公共部分,第二个参数{4,5}代表是第二个链表非公共部分,最后的{6,7}表示的是2个链表的公共部分。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2)
{
vector<int> ans;
ListNode* h=pHead2;
while(pHead1)
{
while(h)
{
if(pHead1->val==h->val) return h;
else
{
h = h->next;
}
}
h = pHead2;
pHead1 = pHead1->next;
}
return NULL;
}
};
25、链表相加(二)
链表 1 为 9->3->7,链表 2 为 6->3,最后生成新的结果链表为 1->0->0->0。
要求:空间复杂度 O(n),时间复杂度 O(n)
输入:[9,3,7],[6,3]
返回值:{1,0,0,0}
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
static const auto io_sync_off=[]()
{
//turn off sync
std::ios::sync_with_stdio(false);
//untie in/out stream;
std::cin.tie(nullptr);
return nullptr;
}();
class Solution {
public:
ListNode* addInList(ListNode* head1, ListNode* head2) {
int a=0,b=0; //记录链表的长度,reverse运行完,a,b返回链表的长度
head1=reverse(head1,a);
head2=reverse(head2,b);
if(a<b) swap(head1,head2); //长的作为链表1
ListNode *record=head1;
bool carry=0;
while(head2) //链表2短,因此只需先遍历链表2
{
int temp=head1->val+head2->val+carry;
carry=0;
if(temp>=10)
{
carry=1;
temp%=10;
}
head1->val=temp; //直接在链表1上面进行修改
head2=head2->next;
if(head2)
{
head1=head1->next;
}
}
while(carry)
{
//在链表1上处理进位
carry=0;
if(head1->next)
{ //判断有没有下一位
head1=head1->next;
if(head1->val == 9)
{
//直接判断是不是9
carry = 1;
//是9则进位
head1->val = 0;
//并且设置为0
}
else head1->val++;
}
else head1->next=new ListNode(0);
}
return reverse(record,a);
// write code here
}
ListNode* reverse(ListNode* ln,int &length)
{
ListNode* pre=nullptr;
ListNode* cur=ln;
ListNode* next=nullptr;
while(cur)
{
next=cur->next; //在指针断开之前,保存下后续结点
cur->next=pre; //改变指向,指向前一个结点
pre=cur;
cur=next;
length++;
}
return pre;
}
};
26、在二叉树中找到两个节点的最近公共祖先
给定一棵二叉树(保证非空)以及这棵树上的两个节点对应的val值 o1 和 o2,请找到 o1 和 o2 的最近公共祖先节点。 注:本题保证二叉树中每个节点的val值均不相同。
要求:时间复杂度 O(n)
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
class Solution {
public:
TreeNode *ret;
bool dfs(TreeNode *root,int o1,int o2)
{
if(!root)
return false;
bool l=dfs(root->left,o1,o2);
bool r=dfs(root->right,o1,o2);
if((l&&r)||((root->val==o1||root->val==o2)&&(l||r)))
{//判断root是否包含o1和o2或root值为o1或o2且o2或o1出现在root子树中
ret=root;
}
return l||r||root->val==o1||root->val==o2;
}
int lowestCommonAncestor(TreeNode* root, int o1, int o2)
{
dfs(root,o1,o2);
return ret->val;
}
};
27、反转字符串
写出一个程序,接受一个字符串,然后输出该字符串反转后的字符串。(字符串长度不超过1000)
要求:空间复杂度O(n),时间复杂度O(n)
class Solution {
public:
string solve(string str) {
// write code here
string ret = "";
for (int i = str.length() - 1; i >= 0; --i)
{
ret += str[i];
}
return ret;
}
};
28、螺旋矩阵
给定一个m x n大小的矩阵(m行,n列),按螺旋的顺序返回矩阵中的所有元素。
要求:空间复杂度 O(nm) ,时间复杂度 O(nm)
输入:[[1,2,3],[4,5,6],[7,8,9]]
返回值:[1,2,3,6,9,8,7,4,5]
class Solution {
public:
vector<int> spiralOrder(vector<vector<int> > &matrix)
{
if(matrix.size() == 0)
return {};
int m = matrix.size(), n = matrix[0].size();
vector<int> ans;
int left_row = 0, left_col = 0, right_row = m - 1, right_col = n - 1; //左上角和右下角坐标
while (left_row <= right_row && left_col <= right_col)
{
//走到最右边
for (int i = left_row; i <= right_col; i++)
ans.push_back(matrix[left_row][i]);
//走到最下边
for (int i = left_row + 1; i <= right_row; i++)
ans.push_back(matrix[i][right_col]);
//往左走到底,left_row != right_row 只有一行时不用走回来,前面已经走了
for (int i = right_col - 1; i >= left_col && left_row != right_row; i--)
ans.push_back(matrix[right_row][i]);
//往上走,left_col != right_col 只有一列时不用走回来,前面已经走了
for (int i = right_row - 1; i >= left_row + 1 && left_col != right_col; i--)
ans.push_back(matrix[i][left_col]);
left_col++;
left_row++;
right_col--;
right_row--;
}
return ans;
}
};
29、 斐波那契数列
大家都知道斐波那契数列,现在要求输入一个正整数 n ,请你输出斐波那契数列的第 n 项。
fib(x) = fib(x−1)+fib(x−2) x>2;
fib(x) = 1 x=1,2。
要求:空间复杂度 O(1),时间复杂度 O(n)
class Solution {
public:
int Fibonacci(int n)
{
vector<int> dp(n + 1);
dp[1] = 1;
dp[2] = 1;
for(int i = 3; i <= n; i++)
{
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
};
30、 最长回文子串
对于长度为n的一个字符串A(仅包含数字,大小写英文字母),请设计一个高效算法,计算其中最长回文子串的长度。
要求:空间复杂度 O(1),时间复杂度 O(n^2)
进阶: 空间复杂度 O(n),时间复杂度 O(n)
class Solution {
public:
int getLongestPalindrome(string A)
{
int res = 0, step;
for (int i = 0; i < A.size(); i += step)
{
int l = i - 1, r = i + 1;
step = 1;
while (r < A.size() && A[i] == A[r])
{
++r;
++step;
}
while (l >= 0 && r < A.size() && A[l] == A[r])
{
++r;
--l;
}
res = max(res, r-l-1);
}
return res;
}
};
31、三数之和
给出一个有n个元素的数组S,S中是否有元素a,b,c满足a+b+c=0?找出数组S中所有满足条件的三元组。
空间复杂度:O(n^2),时间复杂度 O(n^2)
注意:三元组(a、b、c)中的元素可以按任意顺序排列;解集中不能包含重复的三元组。
输入:[-10,0,10,20,-10,-40]
返回值:[[-10,-10,20],[-10,0,10]]
class Solution {
public:
vector<vector<int> > threeSum(vector<int> &num)
{
vector<vector<int>> ret = {};
int sz = num.size();
if (sz < 3) return ret;
//先排序
sort(num.begin(), num.end());
//遍历数组 选为target 跳过重复
for (int i = 0; i < sz - 2; i++)
{
int l = i + 1; //左指针
int r = sz - 1; //右指针
int tar = -num[i]; //target
while (l < r) {
if (num[l] + num[r] > tar)
{ //太大了 小一点
r--;
}
else if (num[l] + num[r] < tar)
{ //太小了 大一点
l++;
}
else
{ //正好找到家和为-tar的组合
vector<int> tmp_ret = {num[i], num[l], num[r]};
ret.push_back(tmp_ret);
//使l,r跳过重复项
while (r - 1 > l && num[r - 1] == num[r]) r--;
while (l + 1 < r && num[l + 1] == num[l]) l++;
r--, l++;
}
}
//遍历i时防止重复项
while (i + 1 < sz - 2 && num[i] == num[i + 1])
i++;
}
return ret;
}
};
32、重建二叉树
给定节点数为 n 的二叉树的前序遍历和中序遍历结果,请重建出该二叉树并返回它的头结点。
例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示。
提示:
1.vin.length == pre.length
2.pre 和 vin 均无重复元素
3.vin出现的元素均出现在 pre里
4.只需要返回根结点,系统会自动输出整颗树做答案对比
要求:空间复杂度 O(n),时间复杂度 O(n)
输入:[1,2,4,7,3,5,6,8],[4,7,2,1,5,3,8,6]
返回值:{1,2,3,4,#,5,6,#,7,#,#,8}
说明:返回根节点,系统会输出整颗二叉树对比结果,重建结果如题面图示
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin)
{
int vinlen = vin.size();
if(vinlen == 0)
return NULL;
vector<int> pre_left, pre_right, vin_left, vin_right;
//创建根节点
TreeNode* root = new TreeNode(pre[0]);
//找到根节点再中序遍历中的位置
int gen = 0;
for(int i = 0; i < vinlen; i++)
{
if(vin[i] == pre[0])
{
gen = i;
break;
}
}
//找到在左边的结点
for(int i = 0; i < gen; i++)
{
vin_left.push_back(vin[i]);
pre_left.push_back(pre[i+1]);
}
//找到在右边的结点
for(int i = gen + 1; i < vinlen; i++)
{
vin_right.push_back(vin[i]);
pre_right.push_back(pre[i]);
}
//递归,利用返回值来插入,妙的离谱
root->left = reConstructBinaryTree(pre_left, vin_left);
root->right = reConstructBinaryTree(pre_right, vin_right);
return root;
}
};
33、最长上升子序列(三)
给定数组 arr ,设长度为 n ,输出 arr 的最长上升子序列。(如果有多个答案,请输出其中 按数值(注:区别于按单个字符的ASCII码值)进行比较的 字典序最小的那个)
要求:空间复杂度 O(n),时间复杂度 O(nlogn)
输入:[1,2,8,6,4]
返回值:[1,2,4]
说明:其最长递增子序列有3个,(1,2,8)、(1,2,6)、(1,2,4)其中第三个 按数值进行比较的字典序 最小,故答案为(1,2,4)
static const auto io_sync_off = []()
{
// turn off sync
std::ios::sync_with_stdio(false);
// untie in/out streams
std::cin.tie(nullptr);
return nullptr;
}();
class Solution {
public:
vector<int> LIS(vector<int>& arr)
{
int n = arr.size();
vector<int> d(n + 1, -1), p(n);
int len = 1;//初始化长度为1,元素为序列第一个数字
d[len] = arr[0];
p[0] = 1;
for(int i = 1; i < n; ++i)
{
if(arr[i] > d[len])
{
//此时将该数字添加到末尾
d[++len] = arr[i];
p[i] = len;
}
else
{
//二分查找恰好合适的位置
int left = 1, right = len, pos = 0;
while(left <= right)
{
int mid = (left + right) / 2;
if(d[mid] < arr[i])
{
pos = mid;
left = mid + 1;
}
else
{
right = mid - 1;
}
}
//对该位置数字进行更新
d[pos + 1] = arr[i];
p[i] = pos + 1;
}
}
vector<int> ans(len);
//逆向查找对应序列值
for(int i = n - 1; i >= 0; --i)
{
if(p[i] == len)
ans[--len] = arr[i];
}
return ans;
}
};
34、求平方根
实现函数 int sqrt(int x) 计算并返回 x 的平方根(向下取整)。
class Solution {
public:
/**
*
* @param x int整型
* @return int整型
*/
int sqrt(int x) {
int i = 1;
int res = 0;
while(x >=0){
x -= i;
++res;
i += 2;
}
return res-1;// write code here
}
};
35、包含min函数的栈
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的 min 函数,输入操作时保证 pop、top 和 min 函数操作时,栈中一定有元素。
此栈包含的方法有:
push(value):将value压入栈中
pop():弹出栈顶元素
top():获取栈顶元素
min():获取栈中最小元素
进阶:栈的各个操作的时间复杂度是 O(1) ,空间复杂度是 O(n)
输入: [“PSH-1”,“PSH2”,“MIN”,“TOP”,“POP”,“PSH1”,“TOP”,“MIN”]
输出: -1,2,1,-1
解析:"PSH-1"表示将-1压入栈中,栈中元素为-1
"PSH2"表示将2压入栈中,栈中元素为2,-1
“MIN”表示获取此时栈中最小元素==>返回-1
"TOP"表示获取栈顶元素==>返回2
"POP"表示弹出栈顶元素,弹出2,栈中元素为-1
"PSH1"表示将1压入栈中,栈中元素为1,-1
"TOP"表示获取栈顶元素==>返回1
“MIN”表示获取此时栈中最小元素==>返回-1
class Solution
{
public:
void push(int value)
{
s_.push_back(value);
}
void pop()
{
s_.erase(--s_.end());
}
int top()
{
return *(--s_.end());
}
int min()
{
int min = 0x7fffffff;
for (auto i : s_)
{
if (i < min)
min = i;
}
return min;
}
private:
vector<int> s_;
};
36、买卖股票的最好时机(一)
假设你有一个数组prices,长度为n,其中prices[i]是股票在第i天的价格,请根据这个价格数组,返回买卖股票能获得的最大收益
1.你可以买入一次股票和卖出一次股票,并非每天都可以买入或卖出一次,总共只能买入和卖出一次,且买入必须在卖出的前面的某一天
2.如果不能获取到任何利润,请返回0
3.假设买入卖出均无手续费
要求:空间复杂度 O(1),时间复杂度 O(n)
class Solution {
public:
int maxProfit(vector<int>& prices) {
int value = 0;
if(prices.size() == 0)
return 0;
int minBuyPrice = prices[0];
for(int i = 1; i < prices.size(); ++i)
{
minBuyPrice = min(minBuyPrice, prices[i]);
value = max(value, prices[i] - minBuyPrice);
}
return value;
}
};
37、 合并k个已排序的链表
合并 k 个升序的链表并将结果作为一个升序的链表返回其头节点。
要求:时间复杂度 O(nlogk)
输入:[{1,2},{1,4,5},{6}]
返回值:{1,1,2,4,5,6}
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *mergeKLists(vector<ListNode *> &lists) {
int k = 1000;
int res[2001];
memset(res, 0, sizeof(res));
ListNode *head, *tNode;
for(int i = 0; i < lists.size(); i++)
{//标记所有出现的数值
tNode = lists[i];
while(tNode)
{
res[tNode->val+k]++;//3代表该数值重复出现3次
tNode = tNode->next;
}
}
head = new ListNode(0);
tNode = head;
for(int i = 0; i < 2001; i++)
{//读取所有已存在的数值
while(res[i] > 0)
{
tNode->next = new ListNode(i-k);
tNode = tNode->next;
res[i]--;//重复次数减1
}
}
return head->next;
}
};
38、字符串的排列
输入一个长度为 n 字符串,打印出该字符串中字符的所有排列,你可以以任意顺序返回这个字符串数组。
例如输入字符串ABC,则输出由字符A,B,C所能排列出来的所有字符串ABC,ACB,BAC,BCA,CBA和CAB。
数据范围:n<10
要求:空间复杂度 O(n!),时间复杂度 O(n!)
class Solution {
public:
set<string> arrange(string str,int n)
{
// 功能:排好前n位
// 递归设置退出条件
set<string> res1;
if(n==0){
res1.insert("");
return res1;
}
set<string> res = arrange(str,n-1);
// 要str前n-1位形成的组合
for(auto s:res)
{
// res中字符串长度为n-1,最后一位下标为n-2,故有n种放置方式
res1.insert(str[n-1]+s);
for(int i=0;i<n-2;i++)
{
res1.insert(s.substr(0,i+1)+str[n-1]+s.substr(i+1));
}
res1.insert(s+str[n-1]);
}
/*
1.没建立递归前后的联系 -> 通过return得到中间变量,一直继承
2.字符串提取某位 不能用[i]?
3.递归的退出条件 n=-1传入是无法跳出来的, 要提前检验
*/
return res1;
}
vector<string> Permutation(string str)
{
// 输入字符串,打印字符所有排列
// aab:aab aba baa
// 状态转移:已知前n-1个的组合,最后一个人有n种站法,分别检查加入
// 递归做的事:得到前一层的结果,在此基础上 重新站队
set<string> ans=arrange(str,str.size());
vector<string> res;
for(auto s:ans)
{
res.push_back(s);
}
return res;
}
};
39、接雨水问题
给定一个整形数组arr,已知其中所有的值都是非负的,将这个数组看作一个柱子高度图,计算按此排列的柱子,下雨之后能接多少雨水。(数组以外的区域高度视为0)
要求:时间复杂度 O(n)
输入:[3,1,2,5,2,4]
返回值:5
说明:数组 [3,1,2,5,2,4] 表示柱子高度图,在这种情况下,可以接 5个单位的雨水,蓝色的为雨水 ,如题面图。
static const auto io_sync_off = []()
{
// turn off sync
std::ios::sync_with_stdio(false);
// untie in/out streams
std::cin.tie(nullptr);
return nullptr;
}();
class Solution {
public:
/**
* max water
* @param arr int整型vector the array
* @return long长整型
*/
long long maxWater(vector<int>& arr)
{
// write code here
int left = 0,right=arr.size()-1;
long long ans = 0;
int left_max = 0,right_max = 0;
while(left<right){
if(arr[left]<arr[right])
{
arr[left]>=left_max ? (left_max = arr[left]):ans+=(left_max-arr[left]);
++left;
}
else
{
arr[right] >= right_max ? (right_max = arr[right]): ans+=(right_max-arr[right]);
--right;
}
}
return ans;
}
};
40、输出二叉树的右视图
请根据二叉树的前序遍历,中序遍历恢复二叉树,并打印出二叉树的右视图
要求: 空间复杂度 O(n),时间复杂度 O(n)
如输入[1,2,4,5,3],[4,2,5,1,3]时,通过前序遍历的结果[1,2,4,5,3]和中序遍历的结果[4,2,5,1,3]可重建出以下二叉树:
所以对应的输出为[1,3,5]。
输入:[1,2,4,5,3],[4,2,5,1,3]
返回值:[1,3,5]
struct Node
{
int val;
Node *left;
Node *right;
Node(int x=0):val(x),left(nullptr),right(nullptr){};
};
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 求二叉树的右视图
* @param xianxu int整型vector 先序遍历
* @param zhongxu int整型vector 中序遍历
* @return int整型vector
*/
Node* buildTree(vector<int> &pre,vector<int> &mid,int le1,int ri1,int le2,int ri2)
{
if(le1>ri1||le1-ri1!=le2-ri2)
return 0;
int index=le2; //首地址
while(mid[index]!=pre[le1])
{
++index;//在中序遍历中首先寻找根节点(前序的第一个数) 该下标的左边的数为左子树,右边的数位右子树
}
Node *p=new Node(pre[le1]); //前序的第一个数为根节点
//卡出前序和中序遍历中的左子树的部分(前后下标值)
p->left=buildTree(pre,mid,le1+1,le1+index-le2,le2,index-1);
//卡出前序和中序遍历中的右子树的部分(前后下标值)
p->right=buildTree(pre,mid,le1+index-le2+1,ri1,index+1,ri2);
return p;
}
vector<int> solve(vector<int>& xianxu, vector<int>& zhongxu)
{
// write code here
//通过前序和后序重建树结构
Node *head=buildTree(xianxu,zhongxu, 0,xianxu.size()-1,0,zhongxu.size()-1);
//res用以存放右视图的值val
vector<int> res;
if(head==0)
return res;
//队列用以存放树,实现层序遍历
queue<Node*> q;
q.push(head);
while(!q.empty())
{
Node *temp=q.front();
res.push_back(temp->val);
for(int i=q.size();i>0;i--)
{
temp=q.front();
q.pop();
if(temp->right)
q.push(temp->right);
if(temp->left)
q.push(temp->left);
}
}
return res;
}
};
41、岛屿数量
给一个01矩阵,1代表是陆地,0代表海洋, 如果两个1相邻,那么这两个1属于同一个岛。我们只考虑上下左右为相邻。
岛屿: 相邻陆地可以组成一个岛屿(相邻:上下左右) 判断岛屿个数。
例如:输入
[[1,1,0,0,0],
[0,1,0,1,1],
[0,0,0,1,1],
[0,0,0,0,0],
[0,0,1,1,1]]对应的输出为3
(注:存储的01数据其实是字符’0’,‘1’)
class Solution {
public:
/**
* 判断岛屿数量
* @param grid char字符型vector<vector<>>
* @return int整型
*/
int solve(vector<vector<char> >& grid)
{
int ildCount = 0;
for (int i = 0; i < grid.size(); ++i)
{
for (int j = 0; j < grid[i].size(); ++j)
{
if (grid[i][j] == '1')
{
zhadao(i, j, grid);
ildCount++;
}
}
}
return ildCount;
}
void zhadao(int x, int y, vector<vector<char>> &grid)
{
//找到1个1之后 把1这个岛炸了 沉海 2 然后继续遍历
grid[x][y] = '2';
if (x - 1 >= 0)
{
if (grid[x-1][y] == '1') zhadao(x-1, y, grid);
}
if (x + 1 < grid.size())
{
if (grid[x+1][y] == '1') zhadao(x+1, y, grid);
}
if (y - 1 >= 0)
{
if (grid[x][y-1] == '1') zhadao(x, y-1, grid);
}
if (y + 1 < grid[x].size())
{
if (grid[x][y+1] == '1') zhadao(x, y+1, grid);
}
}
};
42、二叉树的最大深度
求给定二叉树的最大深度,最大深度是所有叶子节点的深度的最大值。
要求: 时间复杂度 O(n)
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int maxDepth(TreeNode *root)
{
if(root == NULL)return 0;
return 1+max(maxDepth(root->left),maxDepth(root->right));
}
};
43、 判断是否为回文字符串
给定一个长度为 n 的字符串,请编写一个函数判断该字符串是否回文。如果是回文请返回true,否则返回false。字符串回文指该字符串正序与其逆序逐字符一致。
要求:空间复杂度 O(1,时间复杂度 O(n)
static const auto io_sync_off = []()
{
// turn off sync
std::ios::sync_with_stdio(false);
// untie in/out streams
std::cin.tie(nullptr);
return nullptr;
}();
class Solution {
public:
bool judge(string str)
{
// write code here
int start = 0;
int end = str.size()-1;
while(start < end)
{
if(str[start] != str[end])
return false;
start++;
end--;
}
return true;
}
};
44、 单链表的排序
给定一个节点数为n的无序单链表,对其按升序排序。
要求:时间复杂度 O(nlogn)
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类 the head node
* @return ListNode类
*/
ListNode* sortInList(ListNode* head)
{
// write code here
vector<int> temp;
ListNode *p=head;
while(p)
{
temp.push_back(p->val);
p=p->next;
}
p=head;
sort(temp.begin(),temp.end());
int i=0;
while(p)
{
p->val=temp[i++];
p=p->next;
}
return head;
}
};
45、判断是不是平衡二叉树
输入一棵节点数为 n 二叉树,判断该二叉树是否是平衡二叉树。
平衡二叉树(Balanced Binary Tree),具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
要求:空间复杂度O(1),时间复杂度 O(n)
输入:{1,2,3,4,5,6,7}
返回值:true
class Solution {
public:
bool IsBalanced_Solution(TreeNode* pRoot)
{
dfs(pRoot);
return flag;
}
private:
bool flag = 1;
int dfs(TreeNode* root) {
if (!root || !flag) return 0;
int left = dfs(root->left);
int right = dfs(root->right);
int diff = abs(left - right);
if (diff > 1) flag = 0;
return max(left, right) + 1;
}
};
46、数组中出现次数超过一半的数字
给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
要求:空间复杂度:O(1),时间复杂度 O(n)
static const auto io_sync_off =[]()
{
std::ios::sync_with_stdio(false);
cin.tie(nullptr);
return nullptr;
}();
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers)
{
int len=numbers.size();
map<int,int> m;
int res=0;
for(int i=0;i<len;i++)
{
m[numbers[i]]++;
if(m[numbers[i]]>len/2)
{
res=numbers[i];
break;
}
}
return res;
}
};
47、矩阵的最小路径和
给定一个 n * m 的矩阵 a,从左上角开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的数字累加起来就是路径和,输出所有的路径中最小的路径和。
要求:时间复杂度 O(nm)
例如:当输入[[1,3,5,9],[8,1,3,4],[5,0,6,1],[8,8,4,0]]时,对应的返回值为12,
所选择的最小累加和路径如下图所示:
输入:[[1,3,5,9],[8,1,3,4],[5,0,6,1],[8,8,4,0]]
返回值:12
class Solution {
public:
/**
* @param matrix int整型vector<vector<>> the matrix
*/
int minPathSum(vector<vector<int> >& matrix)
{
int m = matrix.size(), n = matrix[0].size();
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (i == 0 && j == 0)
continue;
if (i == 0)
{
//第一行只能从左边走过来
matrix[i][j] += matrix[i][j - 1];
}
else if (j == 0)
{
//第一列只能从上面走下来
matrix[i][j] += matrix[i - 1][j];
}
else
{
//递推公式,取从上面走下来和从左边走过来的最小值+当前坐标的值
matrix[i][j] += min(matrix[i - 1][j], matrix[i][j - 1]);
}
}
}
return matrix[m - 1][n - 1];
}
};
48、表达式求值
请写一个整数计算器,支持加减乘三种运算和括号。
输入:“(2*(3-4))*5”
返回值:-10
class Solution {
public:
int solve(string s) {
// write code here
int ans = 0; //用于返回当前字符串的计算结果
stack<int> sum; //用于求和
char sign = '+'; //记录前一个符号,初始化为+,因为可以看成当前字符串前先加0
int num = 0; //用于将连续数字字符串转化成数字或者记录递归结果
for(int i = 0; i < s.size(); i++)
{ //遍历每一个字符
if(s[i] >= '0' && s[i] <= '9') //先处理数字字符
num = 10 * num + s[i] - '0'; //进位后加个位数
if(s[i] == '(')
{ //对于括号
int left = i++, count = 1; //用left记录最左括号位置,count记录左括号数,i当成右指针右移一格
while(count > 0)
{ //最终目的是找到与最左括号匹配的右括号,类似于栈操作
if(s[i] == '(') count++;
else if(s[i] == ')') count--;
i++;
}
num = solve(s.substr(left + 1, i - left - 2)); //迭代计算括号内数值,注意不要包含最左最右括号,不然会死循环
i--; //此时i是最右括号下一位,需要左移一位防止最右括号在字符串尾时发生越界从而使下面的判定失效
}
if(i == s.size() - 1 || s[i] == '+' || s[i] == '-' || s[i] == '*')
{ //对于字符串尾,或者加减乘,此时我们用的符号是上一次的,结算当前数字
if(sign == '+') sum.push(num); //加法入栈
else if(sign == '-') sum.push(-num); //减法相当于加负数
else if(sign == '*') sum.top() *= num; //乘法与栈顶相乘
sign = s[i]; //更新符号,若为末尾的右括号也无妨,因为马上就退出循环了
num = 0; //重置当前数
}
}
while(!sum.empty())
{ //将栈内所有数字相加
ans += sum.top();
sum.pop();
}
return ans; //返回当前字符串计算结果
}
};
49、 字符串出现次数的TopK问题
给定一个字符串数组,再给定整数 k ,请返回出现次数前k名的字符串和对应的次数。
返回的答案应该按字符串出现频率由高到低排序。如果不同的字符串有相同出现频率,按字典序排序。
对于两个字符串,大小关系取决于两个字符串从左到右第一个不同字符的 ASCII 值的大小关系。
比如"ah1x"小于"ahb",“231”<”32“
字符仅包含数字和字母
要求:空间复杂度 O(n),时间复杂度O(nlogk)
输入:[“123”,“123”,“231”,“32”],2
返回值:[[“123”,“2”],[“231”,“1”]]
说明: "123"出现了2次,记[“123”,“2”],"231"与"32"各出现1次,但是"231"字典序在"32"前面,记[“231”,“1”],最后返回[[“123”,“2”],[“231”,“1”]]
struct cmp
{
bool operator() (pair<string, int> &p1, pair<string, int> &p2)
{
//出现次数较高或者出现次数相同字典序小的优先级高(堆顶的元素优先级最低)
return p1.second > p2.second || (p1.second == p2.second && p1.first < p2.first);
}
};
class Solution {
public:
vector<vector<string> > topKstrings(vector<string>& strings, int k)
{
vector<vector<string> > res;
unordered_map<string, int> umap; //用于统计字符串出现次数
for(string &s: strings) umap[s]++;
priority_queue<pair<string, int>, vector<pair<string, int> >, cmp> pq; //自定义优先队列
for(auto it = umap.begin(); it != umap.end(); it++)
{ //遍历无序map
//当堆元素数小于k直接入堆
if(pq.size() < k) pq.emplace(pair<string, int> {it->first, it->second});
else if(it->second > pq.top().second || (it->second == pq.top().second && it->first < pq.top().first))
{ //否则判断是否能取出堆顶放入新元素
pq.pop();
pq.emplace(pair<string, int> {it->first, it->second});
}
}
while(!pq.empty())
{ //由优先级从小到大依次取出
res.emplace_back(vector<string> {pq.top().first, to_string(pq.top().second)});
pq.pop();
}
reverse(res.begin(), res.end()); //逆转使优先级从大到小
return res; //返回结果
}
};
50、 进制转换
给定一个十进制数 M ,以及需要转换的进制数 N 。将十进制数 M 转化为 N 进制数。
当 N 大于 10 以后, 应在结果中使用大写字母表示大于 10 的一位,如 ‘A’ 表示此位为 10 , ‘B’ 表示此位为 11 。若 M 为负数,应在结果中保留负号。
要求:空间复杂度O(logMN),时间复杂度 O(logMN)
class Solution {
public:
/**
* 进制转换
* @param M int整型 给定整数
* @param N int整型 转换到的进制
* @return string字符串
*/
string solve(int M, int N)
{
// write code here
if(M == 0) return "0";//如果M=0就直接返回
bool flag = false;//记录是不是负数
if(M < 0){
//如果是负数flag=true,M 取相反数
flag = true;
M = -M;
}
string res = "";//返回最终的结果
string jz = "0123456789ABCDEF";//对应进制的某一位
while(M != 0){//就对应转换为N进制的逆序样子
res += jz[M % N];
M /= N;
}
reverse(res.begin(),res.end());//逆序一下才是对应的N进制
if(flag) res.insert(0,"-");//如果是负数就在头位置插入一个-号
return res;
}
};
51、 判断一个链表是否为回文结构
给定一个链表,请判断该链表是否为回文结构。
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
static int x = []
{
std::ios::sync_with_stdio(false);
cin.tie(NULL);
return 0;
}();
class Solution {
public:
bool isPail(ListNode* head)
{
// write code here
if(!head || !head->next) return true;
vector<int> temp;
while(head)
{
temp.push_back(head->val);
head = head->next;
}
int j = temp.size()-1;
int i = 0;
while(i < j)
{
if(temp[i++] != temp[j--]) return false;
}
return true;
}
};
52、编辑距离(二)
给定两个字符串str1和str2,再给定三个整数ic,dc和rc,分别代表插入、删除和替换一个字符的代价,请输出将str1编辑成str2的最小代价。
要求:空间复杂度 O(n),时间复杂度 O(n^2)
class Solution {
public:
/**
* min edit cost
* @param str1 string字符串 the string
* @param str2 string字符串 the string
* @param ic int整型 insert cost
* @param dc int整型 delete cost
* @param rc int整型 replace cost
* @return int整型
*/
int minEditCost(string str1, string str2, int ic, int dc, int rc)
{
// write code here
int n=str1.size(),m=str2.size();
int dp[m+1]; // dp[i]表示对于此时的str1,需要满足和str2的前i个字符相等的最小代价
for(int i=0;i<=m;i++)
{
// 此时str1的长度为0的情况下,我们需要求出str1和str2的前i个字符匹配的最小代价
dp[i]=i*ic;
}
for(int i=1;i<=n;i++)
{
int pre=dp[0];
dp[0]=i*dc;
for(int j=1;j<=m;j++)
{
int ins=dp[j-1]+ic;
int del=dp[j]+dc;
int rep=pre+(str1[i-1]==str2[j-1]?0:rc);
pre=dp[j];
dp[j]=min(ins,min(del,rep));
}
}
return dp[m];
}
};
53、 二叉树根节点到叶子节点的所有路径和
给定一个二叉树的根节点root,该树的节点值都在数字0−9 之间,每一条从根节点到叶子节点的路径都可以用一个数字表示。
1.该题路径定义为从树的根结点开始往下一直到叶子结点所经过的结点;
2.叶子节点是指没有子节点的节点;
3.路径只能从父节点到子节点,不能从子节点到父节点;
4.总节点数目为n。
例如根节点到叶子节点的一条路径是1→2→3,那么这条路径就用123 来代替。
找出根节点到叶子节点的所有路径表示的数字之和
例如: 这颗二叉树一共有两条路径,根节点到叶子节点的路径 1→2 用数字12代替,根节点到叶子节点的路径 1→3 用数字13代替。所以答案为 12+13=25
要求:空间复杂度 O(n),时间复杂度)O(n^2)
进阶:空间复杂度 O(n),时间复杂度 O(n)
class Solution {
public:
int sumNumbers(TreeNode *root)
{
return dfs( root, 0);
}
int dfs(TreeNode *root, int sum)
{
if ( root == nullptr ) return 0;
if ( root->left == nullptr && root->right == nullptr )
return sum * 10 + root->val;
return dfs(root->left, sum * 10 + root->val)
+ dfs(root->right, sum * 10 + root->val);
}
};
54、 二叉树中和为某一值的路径(二)
输入一颗二叉树的根节点root和一个整数expectNumber,找出二叉树中结点值的和为expectNumber的所有路径。
1.该题路径定义为从树的根结点开始往下一直到叶子结点所经过的结点;
2.叶子节点是指没有子节点的节点;
3.路径只能从父节点到子节点,不能从子节点到父节点;
4.总节点数目为n。
如二叉树root为{10,5,12,4,7},expectNumber为22,
则合法路径有[[10,5,7],[10,12]]
输入:{10,5,12,4,7},22
返回值:[[10,5,7],[10,12]]
说明:返回[[10,12],[10,5,7]]也是对的
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
vector<vector<int>> ans;
vector<int> path;
void dfs(TreeNode* root,int target)
{
if(!root) return;
path.push_back(root->val); //当前节点入栈
target -= root->val;
if(root -> left == nullptr && root->right == nullptr && target == 0)
{
ans.push_back(path);
}
dfs(root->left,target); //向左递归
dfs(root->right,target); //向右递归
//回溯
target += root->val;
path.pop_back();
}
vector<vector<int>> FindPath(TreeNode* root,int expectNumber)
{
dfs(root,expectNumber);
sort(ans.begin(),ans.end());
return ans;
}
};
55、 链表内指定区间反转
将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转。
例如:给出的链表为 1→2→3→4→5→NULLm=2,n=4m=2,n=4
返回 1→4→3→2→5→NULL.
要求:时间复杂度 O(n),空间复杂度 O(n)
进阶:时间复杂度 O(n),空间复杂度 O(1)
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
* @param head ListNode类
* @param m int整型
* @param n int整型
* @return ListNode类
*/
ListNode* reverseBetween(ListNode* head, int m, int n)
{
ListNode *mHead = new ListNode(0);
mHead->next = head;
ListNode *cur=head,*pre=mHead,*next=nullptr;;
for(int i=0;i<m-1;++i)
{//cur 指向 m 的位置
pre = cur;
cur = cur->next;
}
//start 指向 m-1 位置; end 指向 m
ListNode *start=pre,*end=cur;
for(int i=m;i<=n;++i)
{//m n 区间反转
next = cur->next;//next 最终指向 n+1 位置
cur->next = pre;
pre = cur;//pre 最终指向 n 位置
cur = next;//cur 最终指向 n+1 位置
}
start->next = pre;//m-1 指向 n 1-->4
end->next = next;//m 指向 n+1 2-->5
return mHead->next;
}
};
56、 不同路径的数目(一)
一个机器人在m×n大小的地图的左上角(起点)。
机器人每次可以向下或向右移动。机器人要到达地图的右下角(终点)。
可以有多少种不同的路径从起点走到终点?
备注:m和n小于等于100,并保证计算结果在int范围内
要求:空间复杂度 O(nm),时间复杂度 O(nm)
进阶:空间复杂度 O(1),时间复杂度 O(min(n,m))
class Solution {
public:
int uniquePaths(int m, int n)
{
vector<int> dp(n+1,1);
for(int i=1;i<m;i++)
{
for(int j=2;j<=n;j++)
{
dp[j]=dp[j]+dp[j-1];
}
}
return dp[n];
}
};
57、 合并区间
给出一组区间,请合并所有重叠的区间。请保证合并后的区间按区间起点升序排列。
要求:空间复杂度 O(n),时间复杂度 O(nlogn)
进阶:空间复杂度 O(val),时间复杂度O(val)
输入:[[10,30],[20,60],[80,100],[150,180]]
返回值:[[10,60],[80,100],[150,180]]
/**
* Definition for an interval.
* struct Interval {
* int start;
* int end;
* Interval() : start(0), end(0) {}
* Interval(int s, int e) : start(s), end(e) {}
* };
*/
static const auto io_sync_off = []()
{
std::ios::sync_with_stdio(false);//关闭输入输出
std::cin.tie(nullptr);//取消两个stream绑定
std::cout.tie(nullptr);//取消cin 和 cout之间的绑定,加快执行效率
return nullptr;
}();
class Solution {
public:
vector<Interval> merge(vector<Interval>& intervals)
{
if (intervals.size() < 2)
return intervals;
sort(intervals.begin(), intervals.end(), [](Interval a, Interval b) {return a.start < b.start; });
Interval inter = intervals[0];
vector<Interval> ans;
for (int i = 1; i < intervals.size(); i++)
{
if (intervals[i].start <= inter.end)
{
inter.end = inter.end < intervals[i].end ? intervals[i].end : inter.end;
}
else
{
ans.push_back(inter);
inter = intervals[i];
}
}
ans.push_back(inter);
return ans;
}
};
58、 最长公共子序列(二)
给定两个字符串str1和str2,输出两个字符串的最长公共子序列。如果最长公共子序列为空,则返回"-1"。目前给出的数据,仅仅会存在一个最长的公共子序列
要求:空间复杂度O(n^2),时间复杂度 O(n^2)
输入:“1A2C3D4B56”,“B1D23A456A”
返回值:“123456”
class Solution {
public:
string LCS(string s1, string s2)
{
// 思想:dp[i][j] 以s1字符串中i结尾,s2字符串中j结尾 相同字符串的长度
// 当s1[i] == s2[j] dp[i][j] = dp[i-1][j-1]+1;
// 当s1[i] != s2[j] dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
if(s1.empty() || s2.empty()) return "-1";
int dp[s1.size()+1][s2.size()+1];
for(int i=0;i<=s1.size();i++) dp[i][0] = 0;
for(int i=0;i<=s2.size();i++) dp[0][i] = 0;
for(int i=1;i<=s1.size();i++)
{
for(int j=1;j<=s2.size();j++)
dp[i][j] = s1[i-1] == s2[j-1]?(dp[i-1][j-1] +1):max(dp[i-1][j],dp[i][j-1]);
}
string res="";
for(int i = s1.size(),j=s2.size();dp[i][j]>0;)
{
if(s1[i-1] == s2[j-1])
{
res = s1[i-1] + res;
i--;
j--;
}
else if(dp[i-1][j]>=dp[i][j-1]) i--;
else j--;
}
return res.empty()?"-1":res;
}
};
59、 在两个长度相等的排序数组中找到上中位数
给定两个递增数组arr1和arr2,已知两个数组的长度都为N,求两个数组中所有数的上中位数。
上中位数:假设递增序列长度为n,为第n/2个数
要求:时间复杂度 O(n),空间复杂度 O(1)
进阶:时间复杂度为O(logN),空间复杂度为O(1)
输入:[1,2,3,4],[3,4,5,6]
返回值:3
说明:总共有8个数,上中位数是第4小的数,所以返回3。
static const auto io_sync_off=[](){//c++11特性的匿名函数
ios_base::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return nullptr;
}();
class Solution {
public:
int findMedianinTwoSortedAray(vector<int>& arr1, vector<int>& arr2)
{
int i=0,j=0,n=arr1.size(),ans;//i,j作为双指针指向两个数组首端元素
while(i+j<n)
{//到遍历过的总元素i+j等于总数组长度一半n时,即找到中位数
if(arr1[i]<arr2[j])
ans=arr1[i++];//ans每次记录较小值,并令指针后移
else ans=arr2[j++];
}
return ans;//返回中位数
}
};
60、 判断一棵二叉树是否为搜索二叉树和完全二叉树
给定一棵二叉树,已知其中的节点没有重复值,请判断该二叉树是否为搜索二叉树和完全二叉树。
输出描述:分别输出是否为搜索二叉树、完全二叉树。
要求:空间复杂度 O(n),时间复杂度 O(n)
注意:空子树我们认为同时符合搜索二叉树和完全二叉树。
输入:{1,#,2}
返回值:[true,false]
说明:由于节点的右儿子大于根节点,无左子树,所以是搜索二叉树但不是完全二叉树
static const auto io_sync_off = []()
{
// turn off sync
std::ios::sync_with_stdio(false);
// untie in/out streams
std::cin.tie(nullptr);
return nullptr;
}();
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
class Solution {
public:
TreeNode *pLast;
vector<bool> judgeIt(TreeNode* root)
{
if( !root )
return {true, true};
pLast = nullptr;
vector<bool> res{my_mid_ergodic(root), true};
queue<TreeNode *> pTN_queue{ {root} };
TreeNode *pTN;
while(pTN = pTN_queue.front())
{
pTN_queue.pop();
pTN_queue.push( pTN->left );
pTN_queue.push( pTN->right );
}
pTN_queue.pop();
while( !pTN_queue.empty() )
{
if( pTN_queue.front() )
{
res[1] = false;
break;
}
pTN_queue.pop();
}
return res;
}
bool my_mid_ergodic(TreeNode *root)
{
if(root)
{
if(root->left && !my_mid_ergodic( root->left ))
return false;
if(pLast && pLast->val >=root->val)
return false;
pLast = root;
if(root->right && !my_mid_ergodic( root->right ))
return false;
}
return true;
}
};
61、 删除有序链表中重复的元素-II
给出一个升序排序的链表,删除链表中的所有重复出现的元素,只保留原链表中只出现一次的元素。
例如:
给出的链表为1→2→3→3→4→4→5, 返回1→2→5
要求:空间复杂度 O(n),时间复杂度 O(n)
进阶:空间复杂度 O(1),时间复杂度 O(n)
输入:{1,2,2}
返回值:{1}
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head)
{
ListNode *dummy = new ListNode(0);//省去判断链表头重复的情况
dummy->next = head;
ListNode *cur=head,*pre=dummy,*q;//记录前一个没重复的节点和当前节点
if(head==NULL||head->next==NULL)
return head;
while(cur&&cur->next)
{//后面元素少于2个则不会重复
bool repeat = 0;//是否重复标志位
while(cur->next && cur->next->val==pre->next->val)
{//存在下一节点并且下一节点的值与pre后面的值相同时(即接下来要判断是否重复的节点值)
repeat = 1;
cur = cur->next;
}
if(repeat)
{//当有重复时前一个没重复的节点指向末尾重复节点的下一位(可能为下一位)
pre->next = cur->next;
}
else
{//否则没重复节点前移
pre = cur;
}
cur = cur->next;
}
return dummy->next;
}
};
62、 把字符串转换成整数(atoi)
写一个函数 StrToInt,实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。传入的字符串可能有以下部分组成:
1.若干空格
2.(可选)一个符号字符(‘+’ 或 ‘-’)
3. 数字,字母,符号,空格组成的字符串表达式
4. 若干空格
转换算法如下:
1.去掉无用的前导空格
2.第一个非空字符为+或者-号时,作为该整数的正负号,如果没有符号,默认为正数
3.判断整数的有效部分:
3.1 确定符号位之后,与之后面尽可能多的连续数字组合起来成为有效整数数字,如果没有有效的整数部分,那么直接返回0;
3.2 将字符串前面的整数部分取出,后面可能会存在存在多余的字符(字母,符号,空格等),这些字符可以被忽略,它们对于函数不应该造成影响;
3.3 整数超过 32 位有符号整数范围 [−2^31, 2^31 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −2^31的整数应该被调整为 −2^31 ,大于 2^31 − 1 的整数应该被调整为 2^31− 1;
4.去掉无用的后导空格。
数据范围:
1.0 <=字符串长度<= 100
2.字符串由英文字母(大写和小写)、数字(0-9)、’ ‘、’+‘、’-’ 和 ‘.’ 组成
class Solution {
public:
int StrToInt(string s)
{
int n = s.length();
// 去除前导空格
int index = 0; //遍历字符串的下标
while(index < n)
{
if (s[index] != ' ')
break;
index++;
}
if(index == n) //除了0就没有了
return 0;
int sign = 1;
// 处理第 1 个非空字符为正负符号
if(s[index] == '+')
index++;
else if(s[index] == '-')
{
sign = -1;
index++;
}
int res = 0;
while(index < n)
{
char c = s[index];
if(c < '0' || c > '9') //非数字跳出
break;
//int型最大最小
if(res > INT_MAX / 10 || (res == INT_MAX / 10 && (c - '0') > INT_MAX % 10))
return INT_MAX;
if(res < INT_MIN / 10 || (res == INT_MIN / 10 && (c - '0') < (-INT_MIN) % 10))
return INT_MIN;
res = res * 10 + sign * (c - '0');
index++;
}
return res;
}
};
63、反转数字
给定一个32位的有符号整数num,将num中的数字部分反转,最后返回反转的结果
1.只反转数字部分,符号位部分不反转
2.反转后整数num超过 32 位的有符号整数的范围 [−2^31, 2^31 − 1] ,返回 0
3.假设本题不允许存储 64 位整数(有符号或无符号,即C++不能使用long long ,Java不能使用long等)
class Solution {
public:
int reverse(int x)
{
long t=0;
while(x)
{
t=10*t+x%10;
x=x/10;
}
return (t>INT_MAX ||t<INT_MIN)?0:t;
}
};
64、矩阵元素查找
已知一个有序矩阵mat,同时给定矩阵的大小n和m以及需要查找的元素x,且矩阵的行和列都是从小到大有序的。设计查找算法返回所查找元素的二元数组,代表该元素的行号和列号(均从零开始)。保证元素互异。
要求:空间复杂度 O(1),时间复杂度 O(n+m)
输入:[[1,2,3],[4,5,6]],2,3,6
返回值:[1,2]
class Solution {
public:
vector<int> findElement(vector<vector<int> > mat, int n, int m, int x)
{
if( n == 0 && m == 0 ) return {};
int i = n-1;
int j = 0;
while( i >=0 && j < m && mat[i][j] != x )
{
if( mat[i][j] > x )
--i;
else
++j;
}
vector<int>res;
res.push_back(i);
res.push_back(j);
return res;
}
};
65、缺失的第一个正整数
给定一个未排序的整数数组nums,请你找出其中没有出现的最小的正整数
进阶: 空间复杂度 O(1),时间复杂度 O(n)
输入:[-2,3,4,1,5]
返回值:2
static const auto io_sync_off = [](){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
return nullptr;
}();
class Solution {
public:
int minNumberDisappeared(vector<int>& nums)
{
int len = nums.size();
vector<int> arr(len);
int idx = 0;
for(int i=0; i < len; i++)
{
if(nums[i] > 0 && nums[i] <= len)
arr[nums[i]-1] = 1;
}
for(int i=0; i < arr.size(); i++)
{
if(arr[i] < 1) return i+1;
}
return len+1;
}
};
66、链表的奇偶重排
给定一个单链表,请设定一个函数,将链表的奇数位节点和偶数位节点分别放在一起,重排后输出。注意是节点的编号而非节点的数值。
要求:空间复杂度 O(n),时间复杂度 O(n)
输入:{1,4,6,3,7}
返回值:{1,6,7,4,3}
说明:1->4->6->3->7->NULL
重排后为 1->6->7->4->3->NULL
奇数位节点有1,6,7,偶数位节点有4,3。重排后为1,6,7,4,3
static const auto io_sync_off =[]()
{
//解除流缓冲区
std::ios::sync_with_stdio(false);
//解除cin与cout间的绑定
std::cin.tie(nullptr);
return nullptr;
}();
class Solution {
public:
ListNode* oddEvenList(ListNode* head)
{
if(head==nullptr||head->next==nullptr)
return head;
ListNode* p1=head;
ListNode* p2=head->next;
ListNode* head2=p2;
while(p2!=nullptr&&p2->next!=nullptr)
{
p1->next=p2->next;
p1=p1->next;
p2->next=p1->next;
p2=p2->next;
}
p1->next=head2;
return head;
}
};
67、二叉树中的最大路径和
二叉树里面的路径被定义为:从该树的任意节点出发,经过父=>子或者子=>父的连接,达到任意节点的序列。
注意:1.同一个节点在一条二叉树路径里中最多出现一次
2.一条路径至少包含一个节点,且不一定经过根节点
输入:{-20,8,20,#,#,15,6}
返回值:41
其中一条最大路径为:15=>20=>6,路径和为15+20+6=41
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
static int x=[]
{
std::ios::sync_with_stdio(false);
cin.tie(NULL);
return 0;
}();
class Solution {
public:
int ans=-0x3f3f3f3f;
int dfs(TreeNode*root)
{
if(!root)return 0;
int l=dfs(root->left);
int r=dfs(root->right);
int m=root->val;
ans=max(ans,m+(r>0?r:0)+(l>0?l:0));
return m+max(max(l,r),0);
}
int maxPathSum(TreeNode* root)
{
return max(ans,dfs(root));
}
};
68、 对称的二叉树
给定一棵二叉树,判断其是否是自身的镜像(即:是否对称)
例如:下面这棵二叉树是对称的
输入:{1,2,2,3,4,4,3}
返回值:true
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
// step 1:两种方向的前序遍历,同步过程中的当前两个节点,同为空,属于对称的范畴。
// step 2:当前两个节点只有一个为空或者节点值不相等,已经不是对称的二叉树了。
// step 3:第一个节点的左子树与第二个节点的右子树同步递归对比,第一个节点的右子树与第二个节点的左子树同步递归比较。
class Solution {
public:
bool recursion(TreeNode* root1, TreeNode* root2)
{
//可以两个都为空
if(root1 == NULL && root2 == NULL)
return true;
//只有一个为空或者节点值不同,必定不对称
if(root1 == NULL || root2 == NULL || root1->val != root2->val)
return false;
//每层对应的节点进入递归
return recursion(root1->left, root2->right) && recursion(root1->right, root2->left);
}
bool isSymmetrical(TreeNode* pRoot)
{
return recursion(pRoot, pRoot);
}
};
69、 括号生成
给出n对括号,请编写一个函数来生成所有的由n对括号组成的合法组合。
例如,给出n=3,解集为:
“((()))”, “(()())”, “(())()”, “()()()”, “()(())”
要求:空间复杂度 O(n),时间复杂度O(2^n)
输入:2
返回值:[“(())”,“()()”]
class Solution {
public:
string res = ""; // 工具字符串
//nums :存储字符结果的集合
//left : 左括号剩余的数量
//right: 右括号剩余的数量
void dfs(vector<string>& nums, int left, int right)
{
if (left == 0 && right == 0)
{// 当左右括号都剩余为0时,将字符串加进集合并结束函数
nums.push_back(res);
return;
}
// 生成左括号
if (left > 0)
{ // 当左括号数量不为0时方可生成左括号
res.push_back('('); // 生成左括号
dfs(nums, left - 1, right); // 递归
res.pop_back(); // 撤销更改,回溯
}
// 生成右括号
if (left < right)
{ // 已经生成的右括号数量不能大于已经生成的左括号数量
res.push_back(')'); // 和上面同理
dfs(nums, left, right - 1);
res.pop_back();
}
}
vector<string> generateParenthesis(int n)
{
vector<string>res;
dfs(res, n, n);
return res;
}
};
70、顺时针旋转矩阵
有一个nxn整数矩阵,请编写一个算法,将矩阵顺时针旋转90度。
给定一个nxn的矩阵,和矩阵的阶数n,请返回旋转后的nxn矩阵。
要求:空间复杂度 O(n^2),时间复杂度 O(n^2)
进阶:空间复杂度 O(1),时间复杂度 O(n^2)
输入:[[1,2,3],[4,5,6],[7,8,9]],3
1 | 2 | 3 | 7 | 4 | 1 | ||
---|---|---|---|---|---|---|---|
4 | 5 | 6 | 8 | 5 | 2 | ||
7 | 8 | 9 | 9 | 6 | 3 |
返回值:[[7,4,1],[8,5,2],[9,6,3]]
class Solution {
public:
vector<vector<int> > rotateMatrix(vector<vector<int> > mat, int n)
{
if(n == 0)
return mat;
// 矩阵顺时针旋转 90° 等价于 先上下翻转 再沿对角线翻转
int rows = mat.size();
int cols = mat[0].size();
for(int i=0;i<rows/2;i++)
for(int j=0;j<cols;j++)
{
swap(mat[i][j],mat[rows-1-i][j]);
}
for(int i=0;i<rows;i++)
for(int j=i+1;j<cols;j++)
{
swap(mat[i][j],mat[j][i]);
}
return mat;
}
};
华机简单到难
71 字符串反转
接受一个只包含小写字母的字符串,然后输出该字符串反转后的字符串。(字符串长度不超过1000)
输入:abcd
输出:dcba
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
string str;
cin>>str;
for(int i=str.size()-1;i>=0;i--)
cout<<str[i];
return 0;
}
72 数字颠倒
输入一个整数,将这个整数以字符串的形式逆序输出。
程序不考虑负数的情况,若数字含有0,则逆序形式也含有0,如输入为100,则输出为001
输入:1516000
输出:0006151
#include<iostream>
#include<string>
using namespace std;
int main(){
int data;
string str;
cin>>data;
str = to_string(data);
string::reverse_iterator it;
for(it=str.rbegin();it!=str.rend();it++)
cout<<*it;
return 0;
}
73 求int型正整数在内存中存储时1的个数
输入描述: 输入一个整数(int类型)
输出描述: 这个数转换成2进制后,输出1的个数
#include <iostream>
using namespace std;
int main(void)
{
int in;
int ct=0;
cin>>in;
int len = sizeof(int)*8;
for(int i=0;i<len-1;i++)
{
if(in&1) ct++;
in>>=1;//等价于in = in>>1;即将二进制每一位上的数都向右移动一位
}
cout<<ct<<endl;
return 0;
}
74 四则运算
输入一个表达式(用字符串表示),求这个表达式的值。
输入:3+2*{1+2*[-4/(8-6)+7]}
输出:25
#include<iostream>
#include<stack>
#include<string>
using namespace std;
int pos=0;
int compute(string & data)
{
int len = data.size();
int num = 0;
char flag = '+';
stack<int> st;
while(pos<len){
//括号判断
if(data[pos]=='{'||data[pos]=='['||data[pos]=='(')
{
pos++;
num = compute(data);
}
//数字判断
while(isdigit(data[pos]))
{
num = num*10+data[pos]-'0';
pos++;
}
//符号判断
switch(flag)
{
case'+':st.push(num);break;
case'-':st.push(-num);break;
case'*':
{
int temp = st.top();
temp*=num;
st.pop();
st.push(temp);
break;
}
case'/':
{
int temp = st.top();
temp/=num;
st.pop();
st.push(temp);
break;
}
}
num = 0;
flag = data[pos];
//括号判断
if(data[pos]=='}'||data[pos]==']'||data[pos]==')')
{
pos++;
break;
}
pos++;
}
int sum = 0;
while(st.size())
{
sum+=st.top();
st.pop();
}
return sum;
}
int main()
{
string data;
while(cin>>data)
{
pos = 0;
cout<<compute(data)<<endl;
}
}
75 表达式求值
给定一个字符串描述的算术表达式,计算出结果值。
输入字符串长度不超过 100 ,合法的字符包括 ”+, -, *, /, (, )” , ”0-9” 。
#include<iostream>
#include<vector>
#include<list>
#include<algorithm>
#include<set>
#include<string>
using namespace std;
int i=0;
int computer(string &str)
{
int num=0;
char flag='+';
list<int> st;
while(i<str.length())
{
if(str[i]=='(')
{
i++;
num=computer(str);
}
while(str[i]>='0'&&str[i]<='9'&&i<str.length())
{
num=num*10+str[i]-'0';
i++;
}
switch(flag)
{
case '+':
st.push_back(num);
break;
case '-':
st.push_back(-num);
break;
case '*':
{
int pro=st.back();
st.pop_back();
st.push_back(pro*num);
break;
}
case '/':
{
int pro=st.back();
st.pop_back();
st.push_back(pro/num);
break;
}
}
num=0;
flag=str[i];
if (str[i] == ')')
{
i++;
break;
}
i++;
}
int sum=0;
while(st.size())
{
sum+=st.back();
st.pop_back();
}
return sum;
}
int main()
{
string str;
while(cin>>str)
{
cout<<computer(str)<<endl;
}
}
76 百钱买百鸡问题
公元五世纪,我国古代数学家张丘建在《算经》一书中提出了“百鸡问题”:鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。百钱买百鸡,问鸡翁、鸡母、鸡雏各几何?现要求你打印出所有花一百元买一百只鸡的方式。
输入描述:输入任何一个整数,即可运行程序。
输出描述: 输出有数行,每行三个整数,分别代表鸡翁,母鸡,鸡雏的数量
#include <iostream>
using namespace std;
int main()
{
int a, b, c;
for(int a=0;a<=20;a++)
{
for (int b=0;b<34;b++)
{
int left = 100 - 5 * a - 3 * b;//剩下的钱
c = left * 3;//鸡雏个数
if (left >= 0 && (a + b + c) == 100)
cout << a << ' ' << b << ' ' << c << endl;
}
}
}
77 完全数计算
完全数(Perfect number),又称完美数或完备数,是一些特殊的自然数。它所有的真因子(即除了自身以外的约数)的和(即因子函数),恰好等于它本身。
例如:28,它有约数1、2、4、7、14、28,除去它本身28外,其余5个数相加,1+2+4+7+14=28。
输入n,请输出n以内(含n)完全数的个数。
输入:1000
输出:3
思路:开一个数组存储真因子的和,从2开始遍历,每遍历到一个数,就把该数的值加入到对应的倍数所在的数组位置,如果数组值(即真因子之和)和下标相同,即表示该下标对应的数是完美数。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,ans=0;
cin>>n;
vector<int> a(n+1,1);//每个数都有因子1
for(int i=2;i<=n;i++){
if(a[i]==i)
ans++;
for(int k=2;i*k<=n;k++)
a[i*k]+=i;//i的倍数(即以i为真因子的数)加上i的值
}
cout<<ans;
}
78 截取字符串
输入一个字符串和一个整数 k ,截取字符串的前k个字符并输出
#include <iostream>
#include <string>
using namespace std;
int main(){
string input;
int k;
while(cin>>input>>k){
for(int i=0;i<k;i++)
cout<<input[i];
cout<<endl;
}
return 0;
}
79 图片整理
Lily上课时使用字母数字图片教小朋友们学习英语单词,每次都需要把这些图片按照大小(ASCII码值从小到大)排列收好。请大家给Lily帮忙,通过代码解决。Lily使用的图片使用字符"A"到"Z"、“a"到"z”、"0"到"9"表示。
输入:Ihave1nose2hands10fingers
输出:0112Iaadeeefghhinnnorsssv
#include <iostream>
#include <string>
using namespace std;
int main(){
string str;
cin>>str;
// sort(str.begin(),str.end());
for(int i=0;i<str.size();i++)
for(int j=1+i;j<str.size();j++){
if(int(str[j])<int(str[i])){
char t=str[j];
str[j]=str[i];
str[i]=t;
}
}
}
cout<<str;
}
80 取近似值
写出一个程序,接受一个正浮点数值,输出该数值的近似整数值。如果小数点后数值大于等于 0.5 ,向上取整;小于 0.5 ,则向下取整。
#include <iostream>
using namespace std;
int main()
{
float f = 0.f;
cin >> f;
int num = (int)(f+0.5);
cout << num << endl;
}
81 字符个数统计
编写一个函数,计算字符串中含有的不同字符的个数。字符在 ASCII 码范围内( 0~127 ,包括 0 和 127 ),换行表示结束符,不算在字符里。不在范围内的不作统计。多个相同的字符只计算一次
例如,对于字符串 abaca 而言,有 a、b、c 三种不同的字符,因此输出 3 。
#include <iostream>
#include <unordered_map>
using namespace std;
int main(){
string s;
unordered_map<char,int> mp;
while(cin>>s){
int n=s.size();
for(int i=0;i<n;i++)
mp[s[i]]++;
cout<<mp.size()<<endl;
}
}
82 走方格的方案数
请计算n*m的棋盘格子(n为横向的格子数,m为竖向的格子数)从棋盘左上角出发沿着边缘线从左上角走到右下角,总共有多少种走法,要求不能走回头路,即:只能往右和往下走,不能往左和往上走。
注:沿棋盘格之间的边缘线行走
数据范围: 1≤n,m≤8
输入描述:输入两个正整数n和m,用空格隔开。(1≤n,m≤8)
输出描述:输出一行结果
思路:到达终点要向右走m次,向下走n次,一共走m+n次;在m+n次中挑出m次向右走,其它次向下走; 排列组合C下标m+n上标m;
#include<iostream>;
using namespace std;
int main(){
int m,n;
while(cin>>m){
cin>>n;
int up = 1;//分子
int down = 1;//分母
for(int i = 0;i<n;i++){//m:2 n:2
up *= (m+n)-i;//4*3
down *=i+1;//2*1
}
cout<<up/down<<endl;//6
}
}
83 放苹果
把m个同样的苹果放在n个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?
注意:如果有7个苹果和3个盘子,(5,1,1)和(1,5,1)被视为是同一种分法。数据范围: 0≤m≤10 ,1≤n≤10
输入描述:输入两个int整数
输出描述:输出结果,int型
#include <iostream>
using namespace std;
int GV(int m, int n)
{
if(m==0 || n==1)//剩0个苹果时候或1个盘子时定义为一种解法
return 1;
if(m>=n)//放法可以分成两类
//1、有至少一个盘子空着,f(m,n) = f(m,n-1);
//2、所有盘子都有苹果,相当于可以从每个盘子中拿掉一个苹果,不影响不同放法的数目,即f(m,n) = f(m-n,n).
return GV(m-n, n)+GV(m, n-1);
else//当n>m:必定有n-m个盘子永远空着,去掉它们对摆放苹果方法数目不产生影响
return GV(m,m);
}
int main(){
int m,n;
cin>>m>>n;
cout<<GV(m, n)<<endl;
}
84 统计字符
输入一行字符,分别统计出包含英文字母、空格、数字和其它字符的个数。
输入:1qazxsw23 edcvfr45tgbn hy67uj m,ki89ol.\/;p0-=\][
输出:26 /n 3 /n 10 /n 12
#include<iostream>
#include<string>
using namespace std;
int main(){
string str;
while(getline(cin,str)){
int charnum=0,knum=0,intnum=0,othernum=0;
for(int i=0;i<str.size();i++){
if(str[i]>='A'&str[i]<='Z'||str[i]>='a'&&str[i]<='z'){
charnum++;
i++;
}
else if(str[i]>='0'&&str[i]<='9'){
intnum++;
}
else if(str[i]==' '){
knum++;
}
else{
othernum++;
}
}
cout<<charnum<<endl;
cout<<knum<<endl;
cout<<intnum<<endl;
cout<<othernum<<endl;
}
return 0;
}
85 尼科彻斯定理
验证尼科彻斯定理,即:任何一个整数m的立方都可以写成m个连续奇数之和。
例如:
1^3=1
2^3=3+5
3^3=7+9+11
4^3=13+15+17+19
输入一个正整数m(m≤100),将m的立方写成m个连续奇数之和的形式输出。
输入:6
输出:31+33+35+37+39+41
#include <iostream>
using namespace std;
int main() {
int m,base,i;
while (cin >> m ) {
base=m*(m-1)+1;
for(i=0;i<m-1;i++)
cout<<base+2*i<<'+';
cout<<base+2*i<<endl;
}
}
86 矩阵乘法
第一行包含一个正整数x,代表第一个矩阵的行数
第二行包含一个正整数y,代表第一个矩阵的列数和第二个矩阵的行数
第三行包含一个正整数z,代表第二个矩阵的列数
之后x行,每行y个整数,代表第一个矩阵的值
之后y行,每行z个整数,代表第二个矩阵的值
输入:2 /n 3 /n 2
1 2 3
3 2 1
1 2
2 1
3 3
输出:14 13 /n 10 11
#include<iostream>
#include<vector>
using namespace std;
int main(){
int rowA, colA_rowB, colB;
while (cin >> rowA >> colA_rowB >> colB){
vector<vector<int>> arrA(rowA, vector<int>(colA_rowB, 0));
vector<vector<int>> arrB(colA_rowB, vector<int>(colB, 0));
vector<vector<int>> arrRes(rowA, vector<int>(colB, 0));
for(int i = 0; i < rowA; ++i)
for(int j = 0; j < colA_rowB; ++j)
cin >> arrA[i][j];
for(int i = 0; i < colA_rowB; ++i)
for(int j = 0; j < colB; ++j)
cin >> arrB[i][j];
for(int i = 0; i < rowA; ++i)
for(int j = 0; j < colA_rowB; ++j)
for(int k = 0; k < colB; ++k)
arrRes[i][k] += arrA[i][j] * arrB[j][k];
for(int i = 0; i < rowA; ++i){
for(int j = 0; j < colB-1; ++j)
cout << arrRes[i][j] << " ";
cout << arrRes[i][colB-1] << endl;
}
}
return 0;
}
87 查找输入整数二进制中1的个数
输入一个正整数,计算它在二进制下的1的个数。
注意多组输入输出
#include <iostream>
#include <vector>
using namespace std;
int main(){
int m;
while(cin>>m){
int count = 0;
for (int i = 0; i < 32; i++) //32 位
if ((m >> i) & 1 == 1)//一个数与1按位与结果如果是1则这个数的最末位就是1
count++;
cout<<count<<endl;
}
88 火车进站
给定一个正整数N代表火车数量,0<N<10,接下来输入火车入站的序列,一共N辆火车,每辆火车以数字1-9编号,火车站只有一个方向进出,同时停靠在火车站的列车中,只有后进站的出站了,先进站的才能出站。(就是个栈问题)
要求输出所有火车出站的方案,以字典序排序输出。
输入:3 /n 1 2 3
输出:1 2 3 /n 1 3 2 /n 2 1 3 /n 2 3 1 /n 3 2 1
说明:第一种方案:1进、1出、2进、2出、3进、3出
第二种方案:1进、1出、2进、3进、3出、2出
第三种方案:1进、2进、2出、1出、3进、3出
第四种方案:1进、2进、2出、3进、3出、1出
第五种方案:1进、2进、3进、3出、2出、1出
请注意,[3,1,2]这个序列是不可能实现的。
//对一位大神的双dfs代码进行了注释
#include<vector>
#include<iostream>
#include<algorithm>
#include<stack>
using namespace std;
vector<vector<int>> res;
vector<int> path;
void dfs(vector<int> nums, int index, stack<int> st){
//栈为空的条件很重要,说明后续出栈流程已经完成可以得到完整的出栈路径(顺序)了
if(index >= nums.size() && st.empty()){
res.push_back(path);
}
//入栈并且暂时不弹出 dfs1
if(index < nums.size()){
st.push(nums[index]);
//注意dfs1中的index+1代表继续入栈下一个元素
dfs(nums, index + 1, st);
st.pop();//回溯
}
//入栈后立即弹出 dfs2
if(!st.empty()){
path.push_back(st.top());
st.pop();
//注意dfs2中index不变,因为这里为弹出操作,后续还有元素需要继续入栈
dfs(nums, index, st);
st.push(path.back());//回溯
path.pop_back();
}
}
int main(){
int n;
stack<int> st;
while(cin >> n){
vector<int> nums(n);
for(int i = 0; i < n; ++i)
cin >> nums[i];
dfs(nums, 0, st);
sort(res.begin(), res.end()); //结果按字典序排序
for(int i = 0; i < res.size();++i){
for(int j = 0; j < res[0].size();++j)
cout << res[i][j] << ' ' ;
cout << endl;
}
}
return 0;
}
89 蛇形矩阵
蛇形矩阵是由1开始的自然数依次排列成的一个矩阵上三角形。
输入:4
输出:
1 3 6 10
2 5 9
4 8
7
#include <iostream>
using namespace std;
int main()
{
int n;
cin >> n;
for(int i = 0;i < n;i++){
for(int j = 0;j < n - i;j++){
if(j > 0) cout << " ";
//位置ij = (i+j+1)*(i+j)/2+j+1
//01 = 2*1/2+1+1
//22 = 5*4/2+2+1
cout << (i+j+1)*(i+j)/2+j+1;
}
cout << endl;
}
return 0;
}
90 求最大连续bit数
输入:200
输出:2
说明:200的二进制表示是11001000,最多有2个连续的1
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
while(cin>>n)
{
int count=0;
while(n)
{
// 1111001110011 &
// 1110011100110
// =1110001100010 消去了每个连续1区间的一个1
n=n&(n<<1);
count++;
}
cout<<count<<endl;
}
return 0;
}
91 提取不重复的整数
输入一个 int 型整数,按照从右向左的阅读顺序,返回一个不含重复数字的新的整数。保证输入的整数最后一位不是 0 。
输入:9876673
输出:37689
#include <bits/stdc++.h>
using namespace std;
int main()
{
int num,n;
vector<int> hash(10,0);
cin>>n;
while(n>0)
{
num=n%10;
n/=10;
if(hash[num]==0)
{
hash[num]=1;
cout<<num;
}
}
return 0;
}
92 查找组成一个偶数最接近的两个素数
任意一个偶数(大于2)都可以由2个素数组成,组成偶数的2个素数有很多种情况,本题目要求输出组成指定偶数的两个素数差值最小的素数对。
输入:20
输出:7 /n 13
#include<bits/stdc++.h>
using namespace std;
bool isTrue(int n)
{
for(int i=2;i<=sqrt(n);i++)
{
if(n%i==0)
return false;
}
return true;
}
int main()
{
int x;
while(cin>>x)
{
int n1,n2;
n1=n2=x/2;
while(!isTrue(n1)||!isTrue(n2))
{
n1-=1;
n2+=1;
}
cout<<n1<<endl<<n2<<endl;
}
}
93 挑7
一个数与7有关是指这个数是 7 的倍数,或者是包含 7 的数字(如 17 ,27 ,37 … 70 ,71 ,72 ,73…)
输入:20
输出:3
说明:输入20,1到20之间有关的数字包括7,14,17共3个。
#include<iostream>
#include<string>
using namespace std;
int main(){
int n = 0, count = 0;
cin >> n;
for(int i = 7; i <= n; i++)
{
string cur = to_string(i);
string str = "7";
if(cur.find(str,0) != string::npos || i % 7 == 0)
count++;
}
cout << count << endl;
}
94 字符逆序
输入:I am a student
输出:tneduts a ma I
#include <iostream>
#include <string>
using namespace std;
int main(){
string str;
getline(cin,str);
for(int i = str.size()-1;i>=0;i--)
cout << str[i];
}
95 杨辉三角的变形
每行的每个数,是恰好是它上面的数、左上角数和右上角的数,3个数之和(如果不存在某个数,认为该数就是0)。 求第n行第一个偶数出现的位置。如果没有偶数,则输出-1。例如输入3,则输出2,输入4则输出3,输入2则输出-1。
输入:4
输出:3
思路:本题是找规律的题,只要往下再写几行就可以看出奇偶的规律,而且每行只需要写前几个就可以了,因为题目问的是第一个偶数的index。
于是我们会发现,只有n为1,2时,没有出现偶数,剩下的按照2 3 2 4的规律每四行循环一次。
n | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
---|---|---|---|---|---|---|---|---|---|---|---|
index | -1 | -1 | 2 | 3 | 2 | 4 | 2 | 3 | 2 | 4 | 2 |
n | (对4求余的结果)%4 | |
---|---|---|
4、8、12…… | 0 | 3 |
5、9、13…… | 1 2 | |
6、10、14 …… | 2 | 4 |
7、11、15…… | 3 | 2 |
#include <iostream>
using namespace std;
int main()
{
int n;
while(cin >> n)
{
if(n==1 || n==2)
cout << -1 << endl;
else if(n%4 == 3 || n%4 == 1)
cout << 2 << endl;
else if(n%4 == 0)
cout << 3 << endl;
else
cout << 4 << endl;
}
return 0;
}
96 矩阵乘法计算量估算
输入描述:输入多行,先输入要计算乘法的矩阵个数n,每个矩阵的行数,列数,总共2n的数,最后输入要计算的法则
计算的法则为一个字符串,仅由左右括号和大写字母(‘A’~‘Z’)组成,保证括号是匹配的且输入合法!
输出描述:输出需要进行的乘法次数
输入:3
50 10
10 20
20 5
(A(BC))
输出:3500(计算ABC有两种顺序:((AB)C)或者(A(BC)),前者需要计算15000次乘法,后者只需要3500次)
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int n;
while (cin >> n)
{
vector<vector<int> > num(n, vector<int>(2, 0));//存储n个矩阵的行列数
for (int i = 0; i < n; i++)
for (int j = 0; j < 2; j++)
cin >> num[i][j];
string s;
cin >> s;
int rightp = 0;//统计‘)’的数量
int leftp = 0;//统计‘(’的数量
int k = 0;//统计矩阵个数
int res = 0;
vector<int> cnum;//记录矩阵在字符串中的位置 ABCDE..肯定按顺序出现
for (int i = 0; i < s.size(); i++)
{
if (s[i] != ')')//不是右括号
{
if (s[i] == '(')
leftp++;
else
{
cnum.push_back(k);//0->A 1->B ...
k++;
}
}
else//遍历时遇到右括号,计算
{
rightp++;
if(rightp > leftp)
break;
int x = cnum.back();//cnum中最后一个数
cnum.pop_back();
int y = cnum.back();//cnum中倒数第二个数
cnum.pop_back();
res += num[y][0] * num[y][1] * num[x][1];
num[y][1] = num[x][1];
cnum.push_back(y);
}
}
cout << res << endl;
}
return 0;
}
97 杨辉三角的变形
以上三角形的数阵,第一行只有一个数1,以下每行的每个数,是恰好是它上面的数、左上角数和右上角的数,3个数之和(如果不存在某个数,认为该数就是0)。求第n行第一个偶数出现的位置。如果没有偶数,则输出-1。例如输入3,则输出2,输入4则输出3,输入2则输出-1。
思路:本题是找规律的题,只要往下再写几行就可以看出奇偶的规律,而且每行只需要写前几个就可以了,因为题目问的是第一个偶数的index。于是我们会发现,只有n为1,2时,没有出现偶数,剩下的按照2 3 2 4的规律每四行循环一次。
n | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | … |
---|---|---|---|---|---|---|---|---|---|---|---|
index | -1 | -1 | 2 | 3 | 2 | 4 | 2 | 3 | 2 | 4 | … |
规律为
n | (对4求余的结果)%4 | |
---|---|---|
4、8、12…… | 0 | 3 |
5、9、13…… | 1 | 2 |
6、10、14 …… | 2 | 4 |
7、11、15…… | 3 | 2 |
#include <iostream>
using namespace std;
int main()
{
int n;
while(cin >> n)
{
if(n==1 || n==2)
cout << -1 << endl;
else if(n%4 == 3 || n%4 == 1)
cout << 2 << endl;
else if(n%4 == 0)
cout << 3 << endl;
else
cout << 4 << endl;
}
return 0;
}
98 统计每个月兔子的总数
#include<bits/stdc++.h>
using namespace std;
int a[100];
int main(){
int n;
while(cin>>n){
a[1] = 1;
a[2] = 1;
for(int i=3;i<=n;i++)
a[i] = a[i-1]+a[i-2];
printf("%d\n",a[n]);
}
return 0;
}
99 从单向链表中删除指定值的节点
输入一个单向链表和一个节点的值,从单向链表中删除等于该值的节点,删除后如果链表中无节点则返回空指针。
链表的值不能重复。
构造过程,例如输入一行数据为:
6 2 1 2 3 2 5 1 4 5 7 2 2
则第一个参数6表示输入总共6个节点,第二个参数2表示头节点值为2,剩下的2个一组表示第2个节点值后面插入第1个节点值,为以下表示:
1 2 表示为2->1 链表为2->1
3 2表示为2->3 链表为2->3->1
5 1表示为1->5 链表为2->3->1->5
4 5表示为5->4 链表为2->3->1->5->4
7 2表示为2->7 链表为2->7->3->1->5->4
最后的链表的顺序为 2 7 3 1 5 4,最后一个参数为2,表示要删掉节点为2的值
删除 结点 2 则结果为 7 3 1 5 4
输入描述:输入一行,有以下4个部分:
1 输入链表结点个数
2 输入头结点的值
3 按照格式插入各个结点
4 输入要删除的结点的值
输出描述:输出删除结点后的序列,每个数后都要加空格
#include<iostream>
using namespace std;
struct node{
int data;
node* next;
};
int main(){
int num,val;
int aft,pre;
cin>>num>>val;
//创建头结点
node* head = new node();
head->data = val;
head->next=NULL;
num--;
//一些列插入
while(num--){
cin>>aft>>pre;
//待插入结点
node* newNode = new node();
newNode->data = aft;
newNode->next = NULL;
//查找前一个结点
node *p=head;
while(p){
if(p->data==pre){
break;
}
else{
p = p->next;
}
}
//如果找到则继续插入
if(p){
node* tmp = p->next;
p->next = newNode;
newNode->next = tmp;
}
}
//读入最后一个参数,并删除
int del;
cin>>del;
node* p = head;
if(head){
node* q = head->next;
while(q){
if(q->data==del){
break;
}else{
p = p->next;
q = q->next;
}
}
if(q){
node* tmp = q->next;
p->next = tmp;
delete q;
}
}
p = head;
while(p){
cout<<p->data<<' ';
p = p->next;
}
return 0;
}
100 字符串排序
输入:
5
cap
to
card
two
boat
输出:
boat
cap
card
to
two
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
bool cmp(string a,string b)
{
//return a.compare(b)<0; //升序
return a<b; //两个效果一样
}
int main()
{
int n;
cin>>n;
string str[1001];
for(int i=0;i<n;i++)
cin>>str[i];
sort(str,str+n,cmp);
for(int i=0;i<n;i++)
cout<<str[i]<<endl;
return 0;
}
101 字符串加密
有一种技巧可以对数据进行加密,它使用一个单词作为它的密匙。下面是它的工作原理:首先,选择一个单词作为密匙,如TRAILBLAZERS。如果单词中包含有重复的字母,只保留第1个,将所得结果作为新字母表开头,并将新建立的字母表中未出现的字母按照正常字母表顺序加入新字母表。如下所示:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
T R A I L B Z E S C D F G H J K M N O P Q U V W X Y (实际需建立小写字母的字母表,此字母表仅为方便演示)
上面其他用字母表中剩余的字母填充完整。在对信息进行加密时,信息中的每个字母被固定于顶上那行,并用下面那行的对应字母一一取代原文的字母(字母字符的大小写状态应该保留)。
输入:nihao
ni
输出:le
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
int main()
{
string s,key;
while(cin>>s>>key){
vector<char> miyao;
for(int i=0;i<s.size();i++){
if(s[i]>='a'&&s[i]<='z')
s[i]=s[i]+'A'-'a';
auto it = find(miyao.begin(), miyao.end(), s[i]);
if(it==miyao.end()){//说明不重复
miyao.push_back(s[i]);
}
}
//将A到Z剩余字符存入密钥
for(char i='A';i<='Z';i++){
auto it = find(miyao.begin(), miyao.end(), i);
if(it==miyao.end())
miyao.push_back(i);
}
char out;
//编码,大小写统一对应
for(int i=0;i<key.size();i++){
if(key[i]>='a'&&key[i]<='z'){
out=miyao[key[i]-'a']+32;
}else {
out=miyao[key[i]-'A'];
}
cout<<out;
}
cout<<endl;
}
return 0;
}
102 等差数列
等差数列 2,5,8,11,14。。。。(从 2 开始的 3 为公差的等差数列)
输出求等差数列前n项和
输入:2
输出:7
说明:2+5=7
#include<iostream>
using namespace std;
int main(){
int n;
while(cin >> n){
int x = 2; //数组第一个元素
int sum = 0;
for(int i = 0; i < n; i++) //遍历数组前n项
sum += x + 3 * i; //累加
cout << sum << endl;
}
return 0;
}
103
104
105
106
107
108
109
110
111
11
参考资料:https://www.nowcoder.com