算法题:最大获利,哲学家就餐,和为N整数,爬楼梯,大文件交集,分堆大量硬币

来源:互联网 发布:人工智能 电子书 编辑:程序博客网 时间:2024/06/10 08:44

本部分包括几个算法题:(1)股价序列求最大获利 (2)哲学家就餐问题 (3)求和N的所有非重复整数的集合 (4)一步或两步走楼梯,到N共有多少走法 (5)求两个超大放置url的文件的交集 (6)如何分出两堆正面相等的硬币


(1) 股价序列求最大获利:

题目:一个股价序列Input,里面有N个数值,每个数值表示不同时间段的股价,问求什么时间买卖获利最大及获得的最大利润。时间复杂度O(N),空间复杂度O(1),可以破坏原股价序列。


思路:股票肯定是卖的股价要比买的股价高,才能获得最大的利润,所以本题的思路是首先截取上升的曲线,然后比较每条上升的曲线的gap值,比较gap值即可。本题可以继续优化,后续再优化吧。


public class Counter1 {/** * @param args */public static void main(String[] args) {    int[] input={10,9,2,3,4,3,2,4,5,6,5,4,2,1,8,9};    System.out.println("original length:"+input.length);int j=0;boolean begin=false;for(int i=1;i<input.length;i++){int temp=input[i]-input[i-1];if(temp>0){if(!begin){input[j]=input[i-1];input[j+1]=input[i];j++;begin=true;continue;}if(input[j]!=input[i-1]){input[j+1]=input[i-1];input[j+2]=input[i];j+=2;}else{input[j+1]=input[i];j+=1;}}}j++;input[j]=-1;for(int i=0;i<input.length;i++){if(input[i]!=-1){System.out.println("get upper line i="+i+",val="+input[i]);}else{break;}}System.out.println("extract the gap");j=0;begin=false;for(int i=1;i<input.length;i++){if(input[i]==-1){break;}else{if(input[i]>input[i-1]){if(!begin){input[j]=input[i-1];begin=true;j++;}input[j]=input[i];}else{j++;input[j]=input[i];j++;}}}j++;input[j]=-1;for(int i=0;i<input.length;i++){if(input[i]!=-1){System.out.println("extract the upper i="+i+",val="+input[i]);}else{break;}}System.out.println("compute the gap");        int gap=0;for(int i=1;i<input.length;i+=2){if(input[i]==-1){break;}else{int tgap=input[i]-input[i-1];if(tgap>gap){gap=tgap;}}}System.out.println("the biggest gap="+gap);}}

(2) 哲学家就餐问题, 五个哲学家围在圆桌边, : 每两人间有一只筷子, : 哲学家的行动顺序为 思考-》拿筷子-》吃饭 -》放筷子 -》思考(每一步时间随机),哲学家要吃饭,必须把左右两边的筷子都拿起, : 这样就有可能产生死锁,比如每个哲学家都可能拿起左边的筷子,等待右边的筷子。 设一个数组state[],保存每个哲学家的状态:thinking,hungry,eating


import java.text.SimpleDateFormat;import java.util.Date;import java.util.Random;public class Philosopher extends Thread {public static final int THINKING = 0;public static final int START = 1;public static final int EATING = 2;public static final int FINISHED = 3;// 每步等待0 - 50毫秒public static final int MAX_WAIT = 50;public static Random ran = new Random();private Table table;private int chair;private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss:SS");public Philosopher(Table table, int chair) {this.table = table;this.chair = chair;}public void run() {try {do {switch (table.getStatus(this.chair)) {case Philosopher.THINKING: {Thread.sleep(ran.nextInt(Philosopher.MAX_WAIT));if (table.test(this.chair)) {table.setStatus(this.chair, Philosopher.START);log(chair + " 拿起了筷子");}break;}case Philosopher.START: {Thread.sleep(ran.nextInt(Philosopher.MAX_WAIT));table.setStatus(this.chair, Philosopher.EATING);log(chair + " 开始吃饭 ");break;}case Philosopher.EATING: {Thread.sleep(ran.nextInt(Philosopher.MAX_WAIT));table.setStatus(this.chair, Philosopher.FINISHED);log(chair + " 吃饭完毕, 放下了筷子");break;}case Philosopher.FINISHED: {Thread.sleep(ran.nextInt(Philosopher.MAX_WAIT));table.setStatus(this.chair, Philosopher.THINKING);log(chair + " 开始下一次思考");break;}}} while (table.isRunning());} catch (Exception e) {e.printStackTrace();}}public void log(String msg) {System.out.println(sdf.format(new Date()) +",哲学家"+ msg);}public static void main(String[] args) {// 10个哲学家, 这下搞大了...Table table = new Table(2);table.start();}}class Table {private Philosopher[] all;private int[] status_list;private boolean running = true;private long start_time;// 3秒后结束运行public static final int TIME_OUT = 2000;public Table(int count) {all = new Philosopher[count];status_list = new int[count];for (int i = 0; i < count; i++) {all[i] = new Philosopher(this, i);status_list[i] = Philosopher.THINKING;}}public void start() {start_time = System.currentTimeMillis();for (int i = 0, len = all.length; i < len; i++) {new Thread(all[i]).start();}}public int getStatus(int chair) {return status_list[chair];}public void setStatus(int chair, int status) {status_list[chair] = status;}public boolean test(int chair) {synchronized (this) {if (System.currentTimeMillis() - start_time > Table.TIME_OUT) {this.running = false;}boolean result = false;int previous = this.getStatus((chair == 0) ? all.length - 1: chair - 1); 每个chair的左边筷子,注意第0个chairint next = this.getStatus((chair == all.length - 1) ? 0 : chair + 1); 每个chair的右边筷子,注意最后一个chairif ((previous == Philosopher.THINKING || previous == Philosopher.FINISHED)&& (next == Philosopher.THINKING || next == Philosopher.FINISHED)) {result = true;}return result;}}public boolean isRunning() {return this.running;}}

还有使用图形化界面的方式更加形象的解决此问题

http://www.cnblogs.com/rollenholt/archive/2011/09/15/2178004.html


(3)求和为N的所有数的集合, 描述:对于和20进行分解,分解成一大一小,大的从19开始依次递减,对于小的进行再次分解,递归求解,如:可分解成13 7 其中7又可分解成 6 1,5  2,4 3 3 可分解成2 1,然后依次类推

public class AnySumN {     int n;    AnySumN(int n){        this.n = n;    }         public void f(String string,int num,int max){        for(int i=max;i>0;i--){            String tempString;            if(num+i==n){                tempString = string + " " + String.valueOf(i);                System.out.println(tempString);            }else if(num+i<n && i-1>0){                tempString = string + " " + String.valueOf(i);                f(tempString,num+i,i-1);            }        }    }         public void direct(){        if(n-1>0)            for(int i=n-1;i>0;i--)                if(i-1>0)                    f(String.valueOf(i),i,i-1);    }    public static void main(String[] args) {    AnySumN asn = new AnySumN(6);        asn.direct();    }}
来源于:http://my.csdn.net/oceanethan/code/detail/40605


http://blog.csdn.net/ryj111/article/details/5192969

(3) 一个楼梯有20级,每次走1级或两级,请问从底走到顶一共有多少种走法?
 分析:假设从底走到第n级的走法有f(n)种,关键的关键:走到第n级有两个方法,一个是从(n-1)级走一步,另一个是从第(n-2)级走两步,前者有f(n-1)种方法,后者有f(n-2)种方法,所以有f(n)=f(n-1)+f(n-2),还有f(0)=1,f(1)=1.
递归编程实现

方法1

#include <stdio.h>int f(int n){ if(n==0 || n==1) return 1; else return f(n-1)+f(n-2);}int main(){    printf("%d/n",f(20));    return 0;}

现在来说说动态规划的基本思想

动态规划的关键是发现子问题和怎么记录子问题,以上面的例子说明
(1) 对子问题可递归的求解,当n>1时,f(n)=f(n-1)+f(n-2);否则,f(1)=f(0)=1;
(2) 这些子问题是有重叠的,即求解某个问题时,某些子问题可能需要求解多次。例如求解f(5)时,f(2)就被求解了3次。
在上面两个条件下,用动态规划的方式来求解会高效很多。就是把子问题记录下来,每个子问题只求解一次,从而提高了效率。
方法二
#include <stdio.h> int result[100]; int f(int n) {      int res;      if(result[n]>=0)       return result[n];      if(n==0 || n==1) res=1;      else res=f(n-1)+f(n-2);      result[n]=res;      return res; } int main() {      int i;      for(i=0;i<=20;i++)            result[i]=-1;      printf("%d/n",f(20));      return 0; }
方法三
#include <stdio.h>int f[100];int main(){     int i;  f[0]=1;  f[1]=1;     for(i=2;i<=20;i++)          f[i]=f[i-1]+f[i-2];     printf("%d",f[20]);  return 0;}


方法三是否让你想起了那个兔子繁殖的问题呢?
小结一下
动态规划,采用分治的策略,把求最优解问题分解为求若干子问题的最优解,记录子问题的解,化繁为简,很实用,也很高效。

(5) 给你A,B两个文件,各存放50亿条URL,每条URL占用64字节,内存限制是4G,让你找出A,B文件共同的URL。如果是三个乃至n个文件呢?

有人使用Bloom Filter 来做处理,但是过于麻烦,比较好的方式还是进行(1)将A和B大文件的数据,通过Hash(url)/1000 hash到1000个小文件中,并给这些小文件取带有规则的名字,比如第几个,来源于哪个文件(2)因为Hash和取模后,相同的URL肯定位于顺序相同的文件名中如A-100.txt 和 B-100.txt (3)将相同顺序的小文件分别读到Set中,使用Collection的retainAll即可获取相同的URL

关于字符串的Hash值,可以参考http://www.blogjava.net/jinfei0627/articles/219543.html
不过对于Java来说,应用的是
 /**     * Returns a hash code for this string. The hash code for a     * <code>String</code> object is computed as     * <blockquote><pre>     * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]     * </pre></blockquote>     * using <code>int</code> arithmetic, where <code>s[i]</code> is the     * <i>i</i>th character of the string, <code>n</code> is the length of     * the string, and <code>^</code> indicates exponentiation.     * (The hash value of the empty string is zero.)     *     * @return  a hash code value for this object.     */    public int hashCode() {            int h = hash;            if (h == 0) {            int off = offset;            char val[] = value;            int len = count;            for (int i = 0; i < len; i++) {                h = 31*h + val[off++]; //31 上文构造方法参数mulBase            }            hash = h;        }        return h;    }

使用正则表达式判断一个字符串是否为IP地址
import java.util.regex.Matcher; import java.util.regex.Pattern; public class TestRegex {        public static boolean isboolIP(String ipAddress){           String one="(2[5][0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})";          String ip=one+"\\."+one+"\\."+one+"\\."+one;    Pattern pattern = Pattern.compile(ip);    Matcher matcher = pattern.matcher(ipAddress);     return matcher.matches();   }}

(6)一大堆硬币,有正有反,现在蒙着眼睛如何让你分,并且硬币的正反面摸不出来,只可以进行翻转,如何分堆才能将分成的两堆硬币中正面个数相同。

答案在下面:
设有M个硬币,N个正面,从M中拿出N个来,如果剩下的一堆中个中有L个正面,那么N个中正面的个数为N-L,则再将这个N个全部翻转,则正面的个数为N-(N-L)) =L。
由此两堆中的正面个数必定相等。之前为啥没有想到这个呢?总是将难点定位在从M中拿出几个硬币来,又分不清正面和反面怎么办?何不继续深想一下,更通用的想一下呢?!


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 魅族手机格式化密码忘了怎么办 魅族手机忘记密码了怎么解锁怎么办 手机设置的应用加密忘记密码怎么办 手机上设置应用加密忘记密码怎么办 魅蓝flyme密码忘了怎么办图片 魅族手机经常自动账号锁屏怎么办 魅族锁定后又不知道密码怎么办 魅族手机锁屏锁定了怎么办 魅族手机已锁定怎么办密码忘了 京东抢到了小米8不发货怎么办 第一次网上预约没有就诊卡号怎么办 京东定金交了未发货怎么办 买了没有预售许可证的房子怎么办 买了没有预售证的房子怎么办 苹果手机发烫容易变3g网怎么办 魅族手机有指纹和密码怎么办刷机 魅族手机指纹解锁密码忘了怎么办 魅蓝5s运存占用太多怎么办 魅蓝e2手机照片被删了怎么办 魅蓝e2不小心删除了照片怎么办 魅蓝3s返回键失灵怎么办 糖猫电话手表屏碎了怎么办 魅蓝手机没下安装包强制更新怎么办 老婆赌博输了30多万现在怎么办啊 红米nt2手机通话声音小怎么办? 微信退出后重新登录忘记密码怎么办 微退出后再登录忘记密码了怎么办 忘记微信密码又退出微信怎么办 无线网自家密码忘了也连不上怎么办 无线网密码忘了连接不上怎么办 魅蓝手机插口半夜坏了怎么办 魅族手机换屏后出现跳屏怎么办 小米手机微信小程序转发不出怎么办 苹果手机ad码和密码忘了怎么办 魅族手机摔掉无法开机怎么办 魅族音量+电源键直接开机了怎么办 魅蓝2数字锁机了怎么办 苹果5s蓝屏开不了机怎么办 红米pro更新开发版发热卡怎么办 5s手机音量增大键失灵怎么办 眼睛看手机久了模糊应怎么办