今天做了创新工场涂鸦移动2017校园招聘测试题-A卷-软件工程师的题目,我也不知道这算不算是泄题,再说也不见得我写的算法就是对的。贴出来,希望大家相互学习,相互进步,如有违反XX,不胜荣幸。
链表
1将链表中的所有元素为奇数的节点移到元素为偶数节点的前面,并使奇数之间顺序反转,偶数之间顺序反转。
示例:
交换前链表的顺序 交换后链表的顺序
4→5→7→1→6 ==> 1→7→5→6→4
1 ==> 1 (链表仅含一个元素)
2→1 ==> 1→2
==> (链表为空)C/C++:
链表节点定义为:
struct node {
struct node *next;
int value;
};
struct node *swap(struct node *list);Java:
链表节点定义为:
class Node {
public Node next;
public int value
}
Node swap(Node list)注意点和要求如下:
- swap函数要求对节点的指针/引用进行操作(不得创建任何新的链表节点)
- 不得使用任何库函数/API,如需使用类似功能, 请自行实现
- 不得将链表转化为其他类型数据结构再进行交换,如数组等
算法思路
本题算法不难,就是将奇数逆序排在前面,偶数逆序拍在后面,所以,毫无疑问应该是有两个头结点,一个链接奇数,一个链接偶数,将原链表从头扫描至尾部时,能分别将节点插入到奇偶链表中。代码
import java.util.Scanner;
public class Main{
//链表结构
static class Node {
public Node next;
public int value;
public Node(){
}
public Node(int val){
this.value=val;
}
}
//创建以尾插入的方式创建链表
public Node createListNode(){
System.out.println("请输入节点值以-1结束");
Scanner scan = new Scanner(System.in);
Node pHead= new Node();
int temp;
if((temp=scan.nextInt())==-1){//头结点
return null;
}else{
pHead.value=temp;
}
Node p =pHead;
while((temp=scan.nextInt())!=-1){
Node q = new Node(temp);
p.next=q;
p=p.next;
}
p.next=null;
return pHead;
}
//打印链表
public void display(Node pHead){
while(pHead!=null){
System.out.print(pHead.value+"\t");
pHead=pHead.next;
}
System.out.println();
}
//链表处理
public Node swap(Node list){
Node p = list;
Node qi=null;//存放奇数的链表
Node ou=null;//存放偶数的链表
Node pnext=null;//用于存储处理原链表当前节点的下一个节点
while(p!=null){
pnext=p.next;//下一个节点先存储
if(p.value%2==1){//如果是奇数节点
if(qi==null){//第一个奇数节点
p.next=null;
qi=p;
}else{//其他奇数节点采用头插法链接到奇数链表中
p.next=qi;
qi=p;
}
}
if(p.value%2==0){//如果是偶数节点
if(ou==null){//第一个偶数节点
p.next=null;
ou=p;
}else{//其他偶数节点采用头插法链接到偶数链表中
p.next=ou;
ou=p;
}
}
p=pnext;
}
list=qi;//奇数链表的头节点作为返回链表的头节点
//遍历奇数链表
while(qi!=null){
pnext=qi;
qi=qi.next;
}
//将偶数链表插入到奇数链表末尾
if(pnext!=null){
pnext.next=ou;
}else{//如果没有奇数链表,则直接返回偶数链表
return ou;
}
//返回链表头结点
return list;
}
public static void main(String[] args) {
Main cls = new Main();
Node pHead = new Node();//创建链表头结点
System.out.println("创建链表");
pHead=cls.createListNode();
cls.display(pHead);//打印链表
System.out.println("链表swap之后");
pHead=cls.swap(pHead);//处理链表
cls.display(pHead);//打印链表
}
}
- 结果
创建链表
请输入节点值以-1结束
4 5 7 1 6 -1
4 5 7 1 6
链表swap之后
1 7 5 6 4
正整数n的最少平方和
给一个正整数 n, 找到若干个完全平方数(比如1, 4, 9, … )使得他们的和等于 n。你需要让平方数的个数最少。
给出 n = 12, 返回 3 因为 12 = 4 + 4 + 4。
给出 n = 13, 返回 2 因为 13 = 4 + 9。
算法思路
毫无疑问是采用动态规划。如果有人做过换零钱这种题目,估计这题也就不陌生了,就是问如果有票值为1元、2元、5元,10元,给定输入的一个钱数,用最少的纸币找清,比如12元只需要一张10元和一张2元共两张就可以找清。因此和本题都是希望能用最少的数的和等于一个数n。这题不一样的在于没有固定票值,但是稍微变通一下,试想一个数的平方和最大就是根号向下取正的那个数,比如11,开根号向下取正就是3,所以3、2、1就是找零钱里面的票值。
采用动态规划解决这个问题,假设a[i]存储的是数i需要最少数的平方和,i=1,…,n;j为1,…,sqrt(n)状态转移公式,则a[i]=min(a[i],a[i-j*j]+1)。说明白点就是对于整数n,对于从1到n的开平方根中某个数的选择还是不选择在于最终平方和等于n的数是不是最小决定。代码
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = (int) Math.sqrt(n);
int a[] = new int[n+1];
for(int i=1;i<=n;i++){
a[i]=Integer.MAX_VALUE;
for(int j=1;j<=m&&i>=j*j;j++){
a[i]=Math.min(a[i], a[i-j*j]+1);
}
}
System.out.println(a[n]);
}
}
总结
其实这两题算法应该都不算难,考得还是基本功,当然上面算法多有瑕疵,如有大神发现错误,望不吝赐教!!