二维数组中的查找

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

#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. 【PHP设计模式 08_CeLue.php】策略模式

    <?php /** * [策略模式]----和"简单工厂"模式很相似 * 根据不同运算符计算两个数的运算结果 * 常规方式就是判断运算符然后进行if...else的操作 * ...

  2. 骑士cms(74cms)个人版 整合UC

    1.安装74cms完成后登录总后台在菜单条工具选项中添加uc整合菜单. 在admin/templates/sys/admin_left_tools.htm这个文件中添加 <li >< ...

  3. js比typeof更准确的验证类型方法

    var type = function (o){ var s = Object.prototype.toString.call(o); return s.match(/\[object (.*?)\] ...

  4. sprint2(第七天)

    因为GitHub有时候我们更新不上,然后浪费很多时间,所以我们决定几天上传一次,而且有时候我们的功能在做,不一定一天能做完,所以几天做完一个模块再一起上传比较好.昨天的燃尽图有点错,有个功能做了没有把 ...

  5. 使用jquery再次封装ajax

    $.fn.ajaxSend = function (type, url, postdata, onSuccess) { $.ajax({ async: false, url: url, type: t ...

  6. Poj(2679),SPFA,二级比较

    题目链接:http://poj.org/problem?id=2679 嗯,思路清晰,先DFS看是不是通路,接着就是SPFA找最短路(路是费用,费用相同就比较路的长度). 超哥的代码还有一点问题,初始 ...

  7. C#中进行单元测试

    首先创建一个项目,写一段待测的程序: namespace ForTest { public class Program { static void Main(string[] args) { } pu ...

  8. Acdream Chinese Girls' Amusement

    A - Chinese Girls' Amusement Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Jav ...

  9. 2016年10月15日 星期六 --出埃及记 Exodus 18:26

    2016年10月15日 星期六 --出埃及记 Exodus 18:26 They served as judges for the people at all times. The difficult ...

  10. 2016年7月1日 星期五 --出埃及记 Exodus 14:28

    2016年7月1日 星期五 --出埃及记 Exodus 14:28 The water flowed back and covered the chariots and horsemen--the e ...