本部分包括几个算法题:(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个chair
int next = this.getStatus((chair == all.length - 1) ? 0 : chair + 1); 每个chair的右边筷子,注意最后一个chair
if ((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;
}
方法三是否让你想起了那个兔子繁殖的问题呢?
小结一下
动态规划,采用分治的策略,把求最优解问题分解为求若干子问题的最优解,记录子问题的解,化繁为简,很实用,也很高效。
/**
* 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;
}
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)一大堆硬币,有正有反,现在蒙着眼睛如何让你分,并且硬币的正反面摸不出来,只可以进行翻转,如何分堆才能将分成的两堆硬币中正面个数相同。