剑指offer---3
1.反转单链表,输入链表的头节点,输出该链表,并输出反转后的头节点
这个题目不用再说了,写过N边了
SLnode reverse(SLnode head)
{
SLnode reverse_head = NULL;
SLnode pnode = head->next;
SLnode prev = NULL;
SLnode pnext = NULL;
while(pnode != NULL)
{
pnext = pnode->next;
if(pnext == NULL)
reverse_head = pnode;
pnode->next = prev;
prev = pnode;
pnode = pnext;
}
head->next = reverse_head;
return head;
}
以前自己还写过一段代码,两种方式的思路不同,这种是从第一个节点开始,把它的next指针指向它的前一个节点,直到最后一个节点为止
下一种也是从第一个节点开始,但是把它的下一个节点放到它的前面,比较不容易理解
SLnode reverse(SLnode head)
{
if(head == NULL || head->next == NULL)
return head; SLnode p = NULL;
SLnode tmp = head->next;
while(tmp->next != NULL)
{
p = tmp->next;
tmp->next = p->next;
p->next = head->next;
head->next = p;
}
return head;
}
2.合并排序的链表,使合并后仍然递增,这个也是写了很多边了,递归和非递归实现
SLnode mergelist2(SLnode head1, SLnode head2)
{
if(head1 == NULL)
return head2;
if(head2 == NULL)
return head1;
SLnode MergerHead = NULL;
if(head1->data > head2->data)
{
MergerHead = head1;
MergerHead->next = mergelist2(head1->next, head2);
}
else
{
MergerHead = head2;
MergerHead->next = mergelist2(head1, head2->next);
}
return MergerHead;
}
再一次强调递归和非递归的本质区别,一个是使用系统提供的栈,即函数参数压栈,一个是我们自己使用栈,此处的非递归采用的是迭代,某种程度上来说,也是使用的栈
SLnode mergelist(SLnode head1, SLnode head2)
{
if(head1 == NULL)
return head2;
if(head2 == NULL)
return head1;
SLnode node1 = head1->next;
SLnode node2 = head2->next; SLnode mergehead = (SLnode)malloc(sizeof(SLnode)); if(node1->data > node2->data)
{
mergehead->next = node1;
node1 = node1->next;
}
else
{
mergehead->next = node2;
node2 = node2->next;
} SLnode temp = mergehead->next;
while(node1 != NULL && node2 != NULL)
{
if(node1->data > node2->data)
{
temp->next = node1;
node1 = node1->next;
temp = temp->next;
}
else
{
temp->next = node2;
node2 = node2->next;
temp = temp->next;
}
}
if(node1 != NULL)
temp->next = node1;
if(node2 != NULL)
temp->next = node2; return mergehead;
}
3.输入两颗二叉树,判断B是不是A的子结构
这个题目很有思想,我是看了思路之后才写出来的,需要分为两步考虑,首先从A中查找是否有B的根节点,如果找到了,再比较A的左子树和B的左子树,A的右子树和B的右子树是否相
等,如果找不到,则继续在A的左子树和右子树中查找是否有和B的根节点相同的,直到A的叶子节点为止
#include <stdio.h>
#include <stdlib.h> typedef struct BitreeNode
{
int data;
struct BitreeNode*left, *right;
}BitreeNode; void construct_bitree(BitreeNode **root)
{
int x;
scanf("%d",&x); if(x != -1)
{
*root = (BitreeNode*)malloc(sizeof(struct BitreeNode));
if(*root == NULL)
printf("malloc error\n");
(*root)->data = x;
(*root)->left = NULL;
(*root)->right = NULL; printf("input the left node, -1 to end\n");
construct_bitree(&((*root)->left)); printf("input the right node, -1 to end\n");
construct_bitree(&((*root)->right));
}
}
void print_tree(BitreeNode *root)
{
if(root != NULL)
{
printf("%d\n",root->data);
print_tree(root->left);
print_tree(root->right);
}
} void Free(BitreeNode *root)
{
if(root != NULL)
return;
else
{
Free(root->left);
Free(root->right);
free(root);
}
} int find_subtree_core(BitreeNode *root1, BitreeNode *root2)
{
if(root1 == NULL)
return 0;
if(root2 == NULL)
return 1;
if(root1->data != root2->data)
return 0;
return find_subtree_core(root1->left, root2->right)&&
find_subtree_core(root1->right, root2->right);
} int find_subtree(BitreeNode *root1, BitreeNode *root2)
{
int ret = 0;
if(root1 != NULL && root2 != NULL)
{
if(root1->data == root2->data)
ret = find_subtree_core(root1, root2);
else
{
if(!ret) find_subtree(root1->left, root2);
if(!ret) find_subtree(root1->right, root2);
}
}
return ret;
} void main()
{ BitreeNode *root1 = NULL;
BitreeNode *root2 = NULL; printf("please input the root1:\n");
construct_bitree(&root1);
print_tree(root1); printf("please input the root2:\n");
construct_bitree(&root2);
print_tree(root2); if(find_subtree(root1, root2))
printf("find the subtree\n"); Free(root1);
Free(root2);
}
4.二叉树的镜像,要求输入一个二叉树,输出它的镜像
思路:如果根节点的左右孩子节点存在,就交换根节点的左右孩子节点,如果左右孩子节点存在,再递归调用
void mirror_of_bitree(BitreeNode *root)
{
if(root == NULL || (root->left == NULL)&&(root->right == NULL))
return;
BitreeNode *temp = root->left;
root->left = root->right;
root->right = temp; mirror_of_bitree(root->left);
mirror_of_bitree(root->right);
}
5.顺时针打印一个矩阵,如果输入的是
1 2 3 4
5 6 7 8
打印的是1 2 3 4 8 7 6 5
这个题目我按照自己思路来解决的,没有按照书上给的思路,直接来想就是打印最外面一圈,然后缩小范围,打印里面一圈,直到范围内曾大小为0时为止
#include <stdio.h>
#define column 4
#define row 4
//这个程序是我自己写出来的,虽然比较臃肿和难以理解,但是思路很清晰
void main()
{
int a[row][column] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}; int begin1 = 0, end1 = row-1;
int begin2 = 0, end2 = column-1;
int i = 0, j = 0;
while(i <= end1)
{
if(j > end2)
break;
for( ; j <= end2; j++)
printf("%d\n",a[i][j]);
j--;
i++;
if(i > end1)
break;
for( ; i <= end1; i++)
printf("%d\n",a[i][j]);
j--;
i--;
if(j < begin2)
break;
for( ; j >= begin2; j--)
printf("%d\n",a[i][j]);
i--;
j++;
if(i <= begin1)
break;
for( ; i > begin1; i--)
printf("%d\n",a[i][j]);
i++;
j++;
begin1++;begin2++;
end1--;end2--;
}
}
6.定一个栈的数据结构,并实现一个能够得到最小元素的min函数,调用min,pop,push函数的时间复杂度都是O(1)
首先我们要明白这个题目的入手点在于用栈去实现这样的数据结构,我当时还傻不啦叽的自己去实现一个栈,找到了切入点,我们再来看怎么去实现这个函数,
在栈中添加一个成员变量作为最小元素?那要是这个变量弹出了怎么办?所以,我们可以每次入栈元素的时候就添加一个变量,这个时候我们可以使用辅助栈,这里的关键在于
每次入栈的时候我们要去更新辅助栈中元素,使它的栈顶是最小元素
#include <iostream>
#include <stack>
#include <stdlib.h>
using namespace std; template<class T>
class Stack
{
private:
stack<T> m_data;
stack<T> m_min;
public:
Stack();
~Stack(); void push(T data);
void pop(); const T& min() const;
};
template<class T>
Stack<T>::Stack()
{} template<class T>
Stack<T>::~Stack()
{} template<class T>
void Stack<T>::push(T data)
{
m_data.push(data);
if(!m_min.empty() && data > m_min.top())
m_min.push(m_min.top());//每次入栈都要考虑最小元素的入栈
else
m_min.push(data);
} template<class T>
void Stack<T>::pop()
{
if(m_data.empty())
{
cout<<"the stack is empty"<<endl;
return;
}
m_data.pop();
m_min.pop();
} template<class T>
const T& Stack<T>::min() const
{
return m_min.top();
} int main()
{
Stack<int> SS;
SS.push(2);
SS.push(3);
SS.push(4);
int ret = SS.min();
SS.pop();
cout<<"min num "<<ret<<endl; SS.push(1);
SS.push(8);
SS.pop();
SS.pop();
SS.push(7);
ret = SS.min();
cout<<"min num "<<ret<<endl; return 0;
}
7.一个整数数组里面,除了两个数字外,其它的数字都出现了两次,写出程序找出这两个只出现一次的数字,时间复杂度为O(n),空间复杂度为O(1)
这个题目还是曾经百度的笔试题目,思路是这样的:
既然其它数字都出现了两次,那么所有的数字求异或之后,得到的值就是只出现一次的那两个数字的异或值,然后我们找到这个值的二进制的最右边的那个1,并以此为依据,将这个数
组分为两部分,因为其它出现两次的数字在个各位上的值一样,所以这两部分就分出了这两个数字
一下是我的参考代码:
#include <stdio.h> int find_the_last1(int x)
{
int n = 0;
x = x&~(x-1);
while((1 & x) == 0)
{
x>>1;
n++;
}
return n;
} void num_appear_once(int a[], int n)
{
int ret = 0, ret1 = 0, ret2 = 0, i;
for(i = 0; i < n; i++)
ret ^= a[i];
int m = find_the_last1(ret);
for(i = 0; i < n; i++)
{
if((a[i]>>m)&1)
ret1 ^= a[i];
else
ret2 ^= a[i];
}
printf("%d\t%d\n",ret1, ret2);
} void main()
{
int a[] = {1,2,3,3,2,5,6,1};
num_appear_once(a, 8);
}
类比去年小米校招的题目:在一个长度为n的整形数组a里,除了三个数字只出现一次外,其他的数字都出现了2次。请写程序输出任意一个只出现一次的数字,程序时间和空间复杂度越小越好。例如: a = {1,3,7,9,5,9,4,3,6,1,7},输出4或5或6
这个题目的思路和上面是一样的,只不过是三个数字,所以在我们异或之后,我们可以两两异或,三个数的两两异或就可以分为两组,参考代码:
// lowbit表示的是某个数从右往左扫描第一次出现1的位置
int lowbit(int x)
{
return x&~(x-1);
}
void find(int* a , int n)
{
int i , xors;
xors = 0;
for(i = 0 ; i < n ; ++i)
xors ^= a[i];
// 三个数两两的异或后lowbit有两个相同,一个不同,可以分为两组
int fips = 0;
for(i = 0 ; i < n ; ++i)
fips ^= lowbit(xors ^ a[i]);//这一步是个关键
// 表示的是:flips=lowbit(a^b)^lowbit(a^c)^lowbit(b^c)
int b; // 假设三个只出现一次的其中一个数为b
b = 0;
for(i = 0 ; i < n ; ++i)
{
if(lowbit(xors ^ a[i]) == fips)
b ^= a[i];
}
// 成功找到三个数中一个数
cout<<b<<endl;
}
剑指offer---3的更多相关文章
- 剑指Offer面试题:1.实现Singleton模式
说来惭愧,自己在毕业之前就该好好看看<剑指Offer>这本书的,但是各种原因就是没看,也因此错过了很多机会,后悔莫及.但是后悔是没用的,现在趁还有余力,把这本书好好看一遍,并通过C#通通实 ...
- 剑指Offer面试题:14.链表的倒数第k个节点
PS:这是一道出境率极高的题目,记得去年参加校园招聘时我看到了3次,但是每次写的都不完善. 一.题目:链表的倒数第k个节点 题目:输入一个链表,输出该链表中倒数第k个结点.为了符合大多数人的习惯,本题 ...
- 《剑指offer》面试题12:打印1到最大的n位数
面试题12:打印1到最大的n位数 剑指offer题目12,题目如下 输入数字n,按顺序打印出1到最大的n位十进制数,比如输入3,则打印出1,2,3一直到最大的三位数999 方法一 和面试题11< ...
- 《剑指offer》面试题11: 数值的整数次方
面试题11: 数值的整数次方 剑指offer面试题11,题目如下 实现函数double power(double base,int exponent),求base的exponent次方, 不得使用库 ...
- 剑指 Offer 题目汇总索引
剑指 Offer 总目录:(共50道大题) 1. 赋值运算符函数(或应说复制拷贝函数问题) 2. 实现 Singleton 模式 (C#) 3.二维数组中的查找 4.替换空格 ...
- 面试题目——《剑指Offer》
1.把一个字符串转换成整数——<剑指Offer>P29 2.求链表中的倒数第k个结点——<剑指Offer>P30 3.实现Singleton模式——<剑指Offer> ...
- 剑指offer习题集2
1.把数组排成最小的数 class Solution { public: static bool compare(const string& s1, const string& s2) ...
- 剑指offer习题集1
1.打印二叉树 程序很简单,但是其中犯了一个小错误,死活找不到,写代码要注意啊 这里左右子树,要注意是node->left,结果写成root->left vector<int> ...
- 剑指Offer:面试题20——顺时针打印矩阵(java实现)
题目描述: 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数 字,例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1, ...
- 牛客网上的剑指offer题目
题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 题目:请实现一个函数,将一 ...
随机推荐
- 如何参与一个GitHub开源项目
Github作为开源项目的著名托管地,可谓无人不知,越来越多的个人和公司纷纷加入到Github的大家族里来,为开源尽一份绵薄之力.对于个人来讲,你把自己的项目托管到Github上并不表示你参与了Git ...
- 开始学习编程了…… 2015年九月七日 …… 31岁的Me.
给自己下的命令:做今天开始认认真真地开始学习编程,一年后的今天一定要找到一份编程的工作. 为什么要学编程?:因为不想回以前的圈子,“创业”快三年什么都给“创”没了,咳……,不过呢,倒是领略到编程能带来 ...
- JavaBean学习--练习示例
初识Javabean,没感觉这鸟东西有什么好用的,一定是我太笨了 自己用jsp测试了下,这里用application作用域做个示例 <%@ page language="java&qu ...
- 13、SQL Server 自定义函数
SQL Server 自定义函数 在SQL Server中不仅可以使用系统函数(如:聚合函数,字符串函数,时间日期函数等)还可以根据需要自定义函数. 自定义函数分为标量值函数和表值函数. 其中,标量值 ...
- How do I size a UITextView to its content?
UITextView 自适应高度,搬来一篇stack上的: Is there a good way to adjust the size of a UITextView to conform to ...
- iOS中使用UIWebView与JS进行交互
iOS中使用UIWebView与JS进行交互 前一段忙着面试和复习,这两天终于考完试了,下学期的实习也有了着落,把最近学的东西更新一下,首先是使用UIWebView与JS进行交互 在webView中我 ...
- JAVA-4-斐波列
public class Ch049 { public static void main(String[] args) { // TODO 自动生成的方法存根 int a = 1, b = 1; fo ...
- ReetrantLock Synchronized Atomic的性能对比
之前看到了一篇帖子关于Lock和Synchronized的性能,写的是Lock比Synchronized的性能要好,可是,我试了下,结果却不是这样的,我所使用的JDK的版本是1.7,可能跟原帖作者用的 ...
- Reverse Interger
Reverse digits of an integer. Example1: x = 123, return 321Example2: x = -123, return -321 Have you ...
- Shell test命令
Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值.字符和文件三个方面的测试. 数值测试 参数 说明 -eq 等于则为真 -ne 不等于则为真 -gt 大于则为真 -ge 大于等于 ...