二维数组中的查找

分析:既然已经给定了每一行从左至右递增,那么对于每一行直接二分查找即可,一开始还想着每一列同样查找一次,后来发现每一行查找一遍就能够遍历所有的元素了。

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
#define MaxN 1000
using namespace std; int N, M, x;
int a[MaxN+][MaxN+]; bool bisearch(int *base, int delta, int l, int r, int val) {
int mid, t;
while (l <= r) {
mid = (l + r) >> ;
t = *(base+delta*mid);
if (t < val) l = mid + ;
else if (t > val) r = mid - ;
else return true;
}
return false;
} int main() {
bool exsit;
while (scanf("%d %d", &N, &M) != EOF) {
scanf("%d", &x);
exsit = false;
for (int i = ; i < N; ++i) {
for (int j = ; j < M; ++j) {
scanf("%d", &a[i][j]);
}
}
for (int i = ; i < N && !exsit; ++i) {
exsit = bisearch((int *)(a+i), , , M-, x);
}
puts(exsit ? "Yes" : "No");
}
return ;
}

用两个栈实现队列

分析:不要每次都翻转来翻转去,构造两个栈,一个栈专门用来倒序存放元素,另外一个栈用来顺序存储待出队的元素,如果待出队的元素不为空则输出,否则将前一个栈的元素倒进后一个栈。

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <stack>
using namespace std; stack<int>stk[]; int main() {
char op[];
int N, x;
while (scanf("%d", &N) != EOF) {
while (!stk[].empty()) stk[].pop();
while (!stk[].empty()) stk[].pop();
for (int i = ; i < N; ++i) {
scanf("%s", op);
if (op[] == 'U') {
scanf("%d", &x);
stk[].push(x);
} else {
if (!stk[].empty()) {
printf("%d\n", stk[].top());
stk[].pop();
} else if (stk[].empty()) puts("-1");
else {
while (!stk[].empty()) {
stk[].push(stk[].top());
stk[].pop();
}
printf("%d\n", stk[].top());
stk[].pop();
}
}
}
}
return ;
}

二叉搜索树的后序遍历序列

分析:首先将后序遍历序列求一个前缀的最大值,然后根据后序遍历的规律,一棵子树的最后一个遍历元素为根元素,因此每次取一个序列的最后一个元素在前缀最大值中二分查找某个分界点,使得前半部分的最大值小于该根,前半部分即为根的左孩子,后半部分为右孩子。递归这个过程,并且记录这个划分过程的中序遍历,最后扫描这个序列是否递增即可。

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; int n, a[];
int b[];
int idx, rec[]; void gao(int l, int r) {
/* if (l == r) {
rec[idx++] = a[l];
return;
} */
int p = upper_bound(b+l, b+r, a[r]) - (b+l);
// printf("%d -> [%d, %d] && [%d, %d]\n", a[r], a[l], a[l+p-1], a[l+p], a[r-1]);
if (p) { // 说明有左孩子
gao(l, l+p-);
}
rec[idx++] = a[r];
if (p != r-l) { // 说明有右孩子
gao(l+p, r-);
}
} int main() {
// freopen("1.in", "r", stdin);
while (scanf("%d", &n) != EOF) {
idx = ;
for (int i = ; i <= n; ++i) {
scanf("%d", &a[i]);
b[i] = max(b[i-], a[i]);
// 求出前缀最大值
}
gao(, n);
int flag = true;
// printf("idx = %d\n", idx);
/* for (int i = 0; i < idx; ++i) {
printf("%d ", rec[i]);
}
puts(""); */
for (int i = ; i < idx; ++i) {
if (rec[i] < rec[i-]) {
flag = false;
break;
}
}
puts(flag ? "Yes" : "No");
}
return ;
}

二叉搜索树与双向链表

分析:这题使用字符串处理的方式没得到正确的输入数据,使用递归读入来简化输入。转化为双向链表的递归过程其实就是一个中序遍历的过程,只不过在中序遍历递归结束之后,增加两条链来使得相邻节点相连接。

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; int seq[];
int idx, sta, cnt;
struct Node {
int val;
int pre, nxt; // pre相当于左孩子,nxt相当于右孩子
}e[]; int build() { // 对某一段先序遍历区间进行二叉搜索树的构建
int cur = idx++; // 申请一个节点
e[cur].val = seq[sta++];
if (seq[sta]) { // 如果有左孩子
e[cur].pre = build();
} else {
++sta;
e[cur].pre = ;
}
if (seq[sta]) {
e[cur].nxt = build();
} else {
++sta;
e[cur].nxt = ;
}
return cur;
} void travel(int lp, int p, int d) {
if (e[p].pre) {
travel(p, e[p].pre, );
}
// printf("%d ", e[p].val);
if (e[p].nxt) {
travel(p, e[p].nxt, );
}
if (d == ) { // 说明从左边递归下来
int q = p;
while (e[q].nxt) q = e[q].nxt;
e[q].nxt = lp;
e[lp].pre = q;
}
else if (d == ) {
int q = p;
while (e[q].pre) q = e[q].pre;
e[q].pre = lp;
e[lp].nxt = q;
}
} void read() { // 递归读取数据
scanf("%d", &seq[cnt]);
if (seq[cnt++]) {
read(), read();
}
} void run() {
int rt = build(), head = rt;
travel(-, rt, -);
while (e[head].pre) head = e[head].pre;
int q = head;
while (q) {
printf("%d ", e[q].val);
q = e[q].nxt;
}
puts("");
} int main() {
int T;
scanf("%d", &T);
while (T--) {
sta = cnt = ;
idx = ;
read();
run();
}
return ;
}

数组中出现次数超过一半的数字

分析:最简单的方法O(N),不是建立hash表,而是利用一个数组中超过一半数为同一个数这个特性,记录一个可能的正确值和这个正确值出现的次数,通过当前值是否为假设值来抵消这个假设值出现的次数。最后判定一次这个假设之是否满足过半。

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std; int n, a[]; int main() {
int num, ti, x;
while (scanf("%d", &n) != EOF) {
num = , ti = ;
for (int i = ; i < n; ++i) {
scanf("%d", &a[i]);
if (a[i] != num) {
--ti;
if (!ti) {
num = a[i], ti = ;
}
} else ++ti;
}
ti = ;
for (int i = ; i < n; ++i) {
if (a[i] == num) ++ti;
}
if (ti * > n) printf("%d\n", num);
else puts("-1");
}
return ;
}

把数组排成最小的数

分析:分析两个元素的大小关系只需要比较s1+s2和s2+s1这两个串的关系即可,因为两个元素交换位置与其他元素的值没有关系。

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
using namespace std; int n;
string a[]; char get(const string &s1, const string &s2, int i, int len) {
if (i < len) return s1[i];
else return s2[i-len];
} bool cmp(string s1, string s2) {
int len1 = s1.length(), len2 = s2.length();
int mlen = len1 + len2;
for (int i = ; i < mlen; ++i) {
char p = get(s1, s2, i, len1), q = get(s2, s1, i, len2);
if (p != q) return p < q;
}
} int main() {
while (scanf("%d", &n) != EOF) {
for (int i = ; i < n; ++i) {
cin >> a[i];
}
sort(a, a+n, cmp);
for (int i = ; i < n; ++i) {
printf("%s", a[i].c_str());
}
puts("");
}
return ;
}

丑数

分析:方法一是通过一个优先队列,每次取出最小的元素,然后下一个元素,然后将这个当前最小元素乘以2、3、5后的值加入到优先队列中去,不同于普通的暴力枚举,该方法能够尽可能的减少无效解的空间开销。方法二就是通过已知的前面的序列由三个指针维护好分别乘以这三个数所产生的最小的值。

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
using namespace std; long long rec[];
/*
priority_queue<long long,vector<long long>,greater<long long> >q; void pre() {
set<long long>st;
int cnt = 1500, idx = 1;
q.push(1);
st.insert(1);
while (cnt--) {
rec[idx] = q.top();
q.pop();
long long a = rec[idx]*2;
long long b = rec[idx]*3;
long long c = rec[idx]*5;
if (!st.count(a)) {
q.push(a);
st.insert(a);
}
if (!st.count(b)) {
q.push(b);
st.insert(b);
}
if (!st.count(c)) {
q.push(c);
st.insert(c);
}
++idx;
}
}
*/ void pre() {
int cnt = , idx = ;
rec[idx++] = ;
int pa = , pb = , pc = ;
while (cnt--) {
int x = min(rec[pa]*, min(rec[pb]*, rec[pc]*));
rec[idx++] = x;
if (x == rec[pa]*) pa++;
if (x == rec[pb]*) pb++;
if (x == rec[pc]*) pc++;
}
} int main() {
pre();
int n;
while (scanf("%d", &n) != EOF) {
printf("%d\n", rec[n]);
}
return ;
}

数字在排序数组中出现的次数

分析:这题直接使用map映射读入的10^6个数MLE了,采用离散化询问的1000个数使得空间需求量减少。

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <map>
using namespace std; map<int,int>mp;
int n, m, cnt;
int a[];
int seq[];
int c[];
int ans[]; int main() {
while (scanf("%d", &n) != EOF) {
mp.clear();
memset(ans, , sizeof (ans));
for (int i = ; i < n; ++i) {
scanf("%d", &a[i]);
}
scanf("%d", &m);
for (int i = ; i < m; ++i) {
scanf("%d", &seq[i]);
c[i] = seq[i];
}
sort(c, c+m);
cnt = unique(c, c+m) - c;
for (int i = ; i < cnt; ++i) {
mp[c[i]] = i;
}
for (int i = ; i < n; ++i) {
if (mp.count(a[i])) {
ans[mp[a[i]]]++;
}
}
for (int i = ; i < m; ++i) {
printf("%d\n", ans[mp[seq[i]]]);
}
}
return ;
}

数组中只出现一次的数字

分析:如果将题目中的数字改成只有一个出现一次,其余出现两次,那么直接异或就能够得到答案。现在有两个数值出现了一次,那么先将所有的数异或起来,那么最后的结果就是两个不同的数异或的结果,取出这个数的某一位为1的位,按照这个为1的位将整个数组进行分组,每个分组里面必定含有一个只出现一次的数。因为某位的异或值为1,那么必定是0和1异或的结果。这个解法真的非常的好。

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std; int n;
int a[]; inline int lowbit(int x) {
return x & -x;
} void gao(int x) {
int bound = lowbit(x);
int xx = , yy = ;
for (int i = ; i < n; ++i) {
if (a[i] & bound) xx ^= a[i];
else yy ^= a[i];
}
if (xx > yy) swap(xx, yy);
printf("%d %d\n", xx, yy);
} int main() {
int x;
while (scanf("%d", &n) != EOF) {
x = ;
for (int i = ; i < n; ++i) {
scanf("%d", &a[i]);
x ^= a[i];
}
gao(x);
}
return ;
}

和为S的两个数字

分析:题目其实没有说明输入的数字都是正整数,我的写法是二分出k/2所在位置,然后从0开始往这个分界位置,对于每一个在分界之后寻找匹配的数。由于要求出乘积最小的组合,因此从前往后遇到匹配项即退出,时间复杂度O(nlogn)。另外一种写法是O(n)的,想法是定义两个指针,分别指向收尾,然后向中间靠拢来得到最终的结果。

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std; const int MaxN = int(1e6);
int n, k;
int a[MaxN+]; void getint(int &t) {
char c;
while (c = getchar(), c < '' || c > '');
t = c - '';
while (c = getchar(), c >= '' && c <= '') {
t = t * + c - '';
}
} int main() {
while (scanf("%d %d", &n, &k) != EOF) {
for (int i = ; i < n; ++i) {
getint(a[i]);
}
int x = -, y = -, i, j;
int pos = lower_bound(a, a+n, k/) - a;
if (a[pos] == k/) ++pos;
for (i = ; i < pos; ++i) {
j = lower_bound(a+pos, a+n, k-a[i]) - a;
if (j != n && a[j] == k-a[i]) {
x = a[i], y = a[j];
break;
}
}
printf("%d %d\n", x, y); /* int i, j, x = -1, y = -1;
for (i = 0, j = n-1; i < j;) {
if (a[i] + a[j] > k) --j;
else {
if (a[i] + a[j] == k) {
x = a[i], y = a[j];
break;
}
++i;
}
}
printf("%d %d\n", x, y);*/
}
return ;
}

N个骰子的点数

分析:n个m个面的骰子,通过母函数计算出所有的结果,然后排序即可。

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std; int n, m, tot;
int f[][]; struct Node {
int val, cnt;
friend bool operator < (const Node &a, const Node &b) {
if (a.cnt != b.cnt) return a.cnt > b.cnt;
else return a.val < b.val;
}
}e[]; void gao() {
memset(e, , sizeof (e));
memset(f, , sizeof (f));
tot = ;
int cur = ;
f[!cur][] = ;
for (int i = ; i < n; ++i) {
for (int j = ; j <= ; ++j) {
for (int k = ; k <= m; ++k) {
f[cur][j+k] += f[!cur][j];
}
f[!cur][j] = ;
}
cur = !cur;
}
for (int i = ; i <= ; ++i) {
e[i].val = i, e[i].cnt = f[!cur][i];
tot += e[i].cnt;
}
for (int i = ; i <= ; ++i) {
e[i].cnt = (int)floor(100.0*e[i].cnt/tot+0.5);
}
sort(e, e + );
for (int i = ; i < ; ++i) {
printf("%d %.2f\n", e[i].val, 1.0*e[i].cnt/);
}
puts("");
} int main() {
// freopen("1.in", "r", stdin);
while (scanf("%d %d", &n, &m), n) {
gao();
}
return ;
}

求1+2+……+n

分析:公式是n*(n+1)/2,把n分解成二进制数然后位运算相加。

#include <cstdlib>
#include <cstdio>
using namespace std; int mask[] = {
<<, <<, <<, <<, <<,
<<, <<, <<, <<, <<,
<<, <<, <<, <<, <<,
<<, <<, <<, <<, <<
}; int n; int main() {
while (scanf("%d", &n) != EOF) {
long long ret = ;
ret += ((n+) << ) * (bool)(n & mask[]);
ret += ((n+) << ) * (bool)(n & mask[]);
ret += ((n+) << ) * (bool)(n & mask[]);
ret += ((n+) << ) * (bool)(n & mask[]);
ret += ((n+) << ) * (bool)(n & mask[]);
ret += ((n+) << ) * (bool)(n & mask[]);
ret += ((n+) << ) * (bool)(n & mask[]);
ret += ((n+) << ) * (bool)(n & mask[]);
ret += ((n+) << ) * (bool)(n & mask[]);
ret += ((n+) << ) * (bool)(n & mask[]);
ret += ((n+) << ) * (bool)(n & mask[]);
ret += ((n+) << ) * (bool)(n & mask[]);
ret += ((n+) << ) * (bool)(n & mask[]);
ret += ((n+) << ) * (bool)(n & mask[]);
ret += ((n+) << ) * (bool)(n & mask[]);
ret += ((n+) << ) * (bool)(n & mask[]);
ret += ((n+) << ) * (bool)(n & mask[]);
ret += ((n+) << ) * (bool)(n & mask[]);
ret += ((n+) << ) * (bool)(n & mask[]);
ret += ((n+) << ) * (bool)(n & mask[]);
printf("%lld\n", ret >> );
}
return ;
}

九度-剑指Offer的更多相关文章

  1. 【剑指Offer面试编程题】题目1509:树中两个结点的最低公共祖先--九度OJ

    题目描述: 给定一棵树,同时给出树中的两个结点,求它们的最低公共祖先. 输入: 输入可能包含多个测试样例. 对于每个测试案例,输入的第一行为一个数n(0<n<1000),代表测试样例的个数 ...

  2. 【剑指Offer面试编程题】题目1508:把字符串转换成整数--九度OJ

    题目描述: 将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数. 输入: 输入可能包含多个测试样例. 对于每个测试案例,输入为一个合法或者非法的字符串,代表一个整数n(1<= n&l ...

  3. 【剑指Offer面试编程题】题目1507:不用加减乘除做加法--九度OJ

    题目描述: 写一个函数,求两个整数之和,要求在函数体内不得使用+.-.*./四则运算符号. 输入: 输入可能包含多个测试样例. 对于每个测试案例,输入为两个整数m和n(1<=m,n<=10 ...

  4. 【剑指Offer面试编程题】题目1356:孩子们的游戏(圆圈中最后剩下的数)--九度OJ

    题目描述: 每年六一儿童节,JOBDU都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此.HF作为JOBDU的资深元老,自然也准备了一些小游戏.其中,有个游戏是这样的:首先,让小朋友们围成一个大圈. ...

  5. 【剑指Offer面试编程题】题目1355:扑克牌顺子--九度OJ

    题目描述: LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他 ...

  6. 【剑指Offer面试编程题】题目1360:乐透之猜数游戏--九度OJ

    题目描述: 六一儿童节到了,YZ买了很多丰厚的礼品,准备奖励给JOBDU里辛劳的员工.为了增添一点趣味性,他还准备了一些不同类型的骰子,打算以掷骰子猜数字的方式发放奖品.例如,有的骰子有6个点数(点数 ...

  7. 【剑指Offer面试编程题】题目1362:左旋转字符串--九度OJ

    题目描述: 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果.对于一个给定的字符序列S,请你把其循环左移K位后的序列输出.例如,字符序列S=&qu ...

  8. 【剑指Offer面试编程题】题目1361:翻转单词顺序--九度OJ

    题目描述: JOBDU最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上.同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思.例如,&quo ...

  9. 【剑指Offer面试编程题】题目1354:和为S的连续正数序列--九度OJ

    题目描述: 小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100.但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数).没多久, ...

随机推荐

  1. SuperSocket架构设计示意图【转】

    转自:http://docs.supersocket.net/v1-6/zh-CN/Architecture-Diagrams 中文(中国)Toggle Dropdown v1.6Toggle Dro ...

  2. svn搭建以及可能遇到的问题解决方案

    Svn服务器的安装和配置 1.安装svn服务器端软件从镜像服务器或者YUM源下载安装SVN服务器软件:yum install subversion mkdir /usr/local/svn //创建S ...

  3. HDU 3887:Counting Offspring(DFS序+树状数组)

    http://acm.hdu.edu.cn/showproblem.php?pid=3887 题意:给出一个有根树,问对于每一个节点它的子树中有多少个节点的值是小于它的. 思路:这题和那道苹果树是一样 ...

  4. C#:屏幕显示区域问题

    更改电脑屏幕显示的文字大小后,平面显示区域问题. /// <summary> /// 屏幕显示尺寸 /// </summary> public static Size Revi ...

  5. ecshop搜索出现相关商品的效果滑动下拉效果

    ecshop搜索栏效果如下 所需要的样式我们可以复制到style.css里: /*搜索滑动效果*/ .Menu { position:absolute; top:30px; left:7px; wid ...

  6. 通过HtmlEmail 发送邮件

    今天第一次来上海市虹口图书馆上自习,感觉还是很爽的.自己撸代码学会了发送邮件.啥都不说了,直接撸代码吧! 首先 必须引进来三个jar包: compile 'javax.mail:mail:1.4.7' ...

  7. Tiling 分类: POJ 2015-06-17 15:15 8人阅读 评论(0) 收藏

    Tiling Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8091   Accepted: 3918 Descriptio ...

  8. 关于接收json以及使用json

    Common: FileIO.cs using System; using System.Collections.Generic; //using System.Linq; using System. ...

  9. Unity脚本在层级面板中的执行顺序测试1

    第二篇测试循环时和动态创建时的调用顺序:LINK 测试版本Unity4.6.因为新版本对Transform的排序做了改变,所以不排除旧版本的测试结果不一样.测试时,使用Awake中添加Debug.lo ...

  10. Application_Error异常处理

    /// <summary> /// 捕捉异常 /// </summary> protected void Application_Error() { // 获得前一个异常的实例 ...