LintCode算法入门:

1.A+B的问题

描述

给出两个整数 aa 和 bb , 求他们的和。

你不需要从输入流读入数据,只需要根据aplusb的两个参数a和b,计算他们的和并返回就行。

说明

a和b都是 32位 整数么?

  • 是的

我可以使用位运算符么?

  • 当然可以

样例

如果 a=1 并且 b=2,返回3

思考:

首先肯定要想到用位运算来操作,即用二进制来处理,好,既然想到这里,当然要举个例子来想想,最简单的1+2

1的二进制 ····0001

2的二进制 ····0010

3的二进制 ····0011

那a+b不就等于a|b吗?那么,再来验证下1+3

1的二进制 ····0001

3的二进制 ····0011

4的二进制 ····0100

发现之前的猜想错误了,然后再经过一些其他简单的验算,我们会轻而易举的发现一个规律,如果没有进位,那么a+b = a|b 如果有进位就不成立。

所以接下来要处理进位的问题,我们在用1+3来研究下进位的问题,如果我们忽略有进位的位置后,再加上应该进位的位置,就是我们的值。

                             1的二进制(a) ····0001

                             3的二进制(b) ····0011

                 忽略进位的二进制(c) ····0010(忽略有进位的位),既然忽略了进位,那么接下来肯定要加上进位

                        应该进位的值(d) ····0010

我们的值应该是c+d(但是c和d还是有进位,那么再重复上述操作),即:

                                  c的二进制 ····0010

                                  d的二进制 ····0010

                 忽略进位的二进制(e) ····0000     

                          应该进位的值(f) ····0100

结果就是e+f = 4

解决方式:

step1:先计算a和b(忽略进位)(相当于位运算符a^b)  a^b:二进制的异或运算

step2:计算应该进位的值(进位)(相当于位运算a&b<<1) a&b<<是二进制的与运算,再左移一位

step3:将上面step1的值和step2的值,相加;如果还有进位,则继续执行step1、step2,直至双方有一个为0时,输出另一方这就是相加的结果。

答案1: 

public class Solution {
    /**
     * @param a: An integer
     * @param b: An integer
     * @return: The sum of a and b 
     */
    public int aplusb(int a, int b) {
        // write your code here
        if (a==0)return b;
        if(b==0)return a;
        int c=a^b;//二进制取异或,没有进位
        int d=(a&b)<<1;//相与再向右移一位,取进位
        return aplusb(c,d);
        //将c+d的结果还有进位,代入aplus的方法,直至某一个数为零,输出另一个数就//是结果
    }
}

 

答案2:

public static int add( int number_1, int number_2 )
	{
		int sum = 0;
		int carry = 0;
		do
		{
			sum = number_1 ^ number_2;
			carry = ( number_1 & number_2 ) << 1;
 
 
			number_1 = sum;
			number_2 = carry;
		}
		while ( carry != 0 );
 
 
		return sum;
	}

 

 

2.设计一个算法,计算出n阶乘中尾部零的个数

描述

设计一个算法,计算出n阶乘中尾部零的个数

您在真实的面试中是否遇到过这个题?  是

样例

11! = 39916800,因此应该返回 2

挑战

O(logN)的时间复杂度

分析

1、2、3、4、5、6、7、8、9、10、11、...101

1-101里,每5个数字,有一个数字的阶层尾部产生零 分别是:5、10、15、20、25、...100 共有101/5=20个

又因为:将5、10、15、20、25、...100

变换成5*(1、2、3、4、5、6、...20)里面又有连续的5个数字

所以又可以变换成5*5*(1、2、3、4)

101所以最终带有的零个数就是

101/5=20

20/5=4 

一个24个

设计思路:将n个数据除以5,如果不整除,再放到循环里面求出带有零的个数累加

public class Solution {
    /*
     * @param n: An integer
     * @return: An integer, denote the number of trailing zeros in n!
     */
    public long trailingZeros(long n) {
        // write your code here, try to do it without arithmetic operators.
        long temp=n/5;
        long count=0;
        while(temp!=0){//如果整除,直接返回结果
            count+=temp;//计零的个数
            temp/=5;//不满足temp为零,继续除
        }
            return count;
    }
}

3.主元素

给定一个整型数组,找出主元素,它在数组中的出现次数严格大于数组元素个数的二分之一。

样例

给出数组[1,1,1,1,2,2,2],返回 1

挑战

要求时间复杂度为O(n),空间复杂度为O(1)

分析:

利用在数组中的出现次数严格大于数组元素个数的二分之一来控制

定义一个初始值和计数器,数组的下一个原始不等于初始值,计数器减一 

如果等于初始值计数器加一,如果计数器为一,而输出那时候的值,就是主元素

public class Solution {
    /*
     * @param nums: a list of integers
     * @return: find a  majority number
     */
    public int majorityNumber(List<Integer> nums) {
        // 利用主元素大于N/2来筛选
        int n=1;//存放出现的次数
        int temp=nums.get(0);//假设第一个就是主元素
        for(int i=1;i<nums.size();i++){
            if(temp==nums.get(i))
           { n++;}
           else if(n==1)
           {temp=nums.get(i);
           }
            else 
           { n--;}
            
        }
         return temp;
       
    }
}

 

4、反转一个3位整数

反转一个只有3位数的整数。

样例

123 反转之后是 321
900 反转之后是 9

注意事项

你可以假设输入一定是一个只有三位数的整数,这个整数大于等于100,小于1000。

public class Solution {
    /**
     * @param number: A 3-digit number.
     * @return: Reversed number.
     */
    public int reverseInteger(int number) {
        // write your code here
        int a,b,c,temp;//
        a=number/100;//对一百取余,得百位
        b=(number%100)/10;//得十位
        c=number%10;//得个位
        temp=c*100+b*10+a;//存放反转的数
        return temp;
        
        
    }
}

5、 合并排序数组

样例

给出A=[1,2,3,4],B=[2,4,5,6],返回 [1,2,2,3,4,4,5,6]

挑战

你能否优化你的算法,如果其中一个数组很大而另一个数组很小?

思路:

1.定义一个长度是A+B长度的数组

2.可能出现的情况:

  • 1-A与B都是空数组
  • 2-A与B都不是空数组(长度不为0)
  • 3-A与B其中有一个是空数组
  • 情况1:直接返回新数组
  • 情况2:满足情况2(长度都大于0),比较依次比较A、B对应的元素(数组元素循环比较大小)
  • 小的先存放到数组,当某一个数组全部插入到新数组后,另一个数组,再依次插入新数组;
  • 情况3:直接将另一个数组存放到新数组中;
public class Solution {
    /**
     * @param A: sorted integer array A
     * @param B: sorted integer array B
     * @return: A new sorted integer array
     */
    public int[] mergeSortedArray(int[] A, int[] B) {
        // write your code here
        int[] c=new int[A.length+B.length];//创建一个新的数组,长度为两个长度相加
        int index1=0;//数组A下标
        int index2=0;//数组B下标
        int curr=0;//c数组下标
        //两两不为空的情况
        while(index1<A.length&&index2<B.length)//长度不为空
        {
            if(A[index1]<B[index2])//拿小的
            {
                c[curr]=A[index1];//将小的存在新数组中
                index1++;//第二元素和B的第一个元素比较
            }
            else
            {
                c[curr]=B[index2];
                index2++;
            }
            curr++;
        }
        
        //当B数组全部插进新数组时
        while(index1<A.length)
        {
            c[curr]=A[index1];
            index1++;
            curr++;
            
        }
        //当A数组全部插进新数组时
        while(index2<B.length)
        {
            c[curr]=B[index2];
            index2++;
            curr++;
            
        }
        return c;
        
    }
}

6、反转数组

题目描述:给定一个长度为n的整数数组a,元素均不相同,问数组是否存在这样一个片段,只将该片段翻转就可以使整个数组升序排列。其中数组片段[l,r]表示序列a[l], a[l+1], ..., a[r]。原始数组为

a[1], a[2], ..., a[l-2], a[l-1], a[l], a[l+1], ..., a[r-1], a[r], a[r+1], a[r+2], ..., a[n-1], a[n],

将片段[l,r]反序后的数组是

a[1], a[2], ..., a[l-2], a[l-1], a[r], a[r-1], ..., a[l+1], a[l], a[r+1], a[r+2], ..., a[n-1], a[n]。

 

输入

 

第一行数据是一个整数:n (1≤n≤105),表示数组长度。

第二行数据是n个整数a[1], a[2], ..., a[n] (1≤a[i]≤109)。

 

样例输入

 

4

2 1 3 4

 

输出

 

输出“yes”,如果存在;否则输出“no”,不用输出引号。

 

样例输出

 

yes

 思路:

1、定义两个数组a、b,赋值一样,长度一样;

2、将数组b进行升序;

3、将数组a的元素依次对应和数组b的左右两边依次比较,记录左边开始数组比较不对应的编号left、记录右边开始两个数值比较不相同的编号right。(2134)(1234)左边开始不相等的编号left=0; 右边比较不相等的编号是right=1;

4、最后比较这段不相等的编号之间,是否满足交叉相等的规律(21)(12)a[left+i]==b[right-i];如果满足这个规律,这输出yes

否则输出no;

package com.demo.day8.list;

import java.util.Arrays;
import java.util.Scanner;
/* 翻转数组。
 * 题目描述:给定一个长度为n的整数数组a,元素均不相同,
 * 问数组是否存在这样一个片段,只将该片段翻转就可以使整个数组升序排列
 * 输入第一行数据是一个整数:n (1≤n≤105),表示数组长度。
 * 第二行数据是n个整数a[1], a[2], ..., a[n] (1≤a[i]≤109)。
 * 输出输出“yes”,如果存在;否则输出“no”,不用输出引号。
 */
public class ArrayTest {

	public static void main(String[] args) {
		//从键盘输入数据
		Scanner sc=new Scanner(System.in);
		while(sc.hasNext()) {
		int len=sc.nextInt();//第一个整数是数组的长度
		// 1、定义两个数组a、b,赋值一样,长度一样;
		int[]a=new int[len];//定义个数组A,长度为len
		int[]b=new int[len];//定义个数组B,长度为len
		for(int i=0;i<len;i++) {
			a[i]=sc.nextInt();
			b[i]=a[i];
			}
		//2、将b数组按升序排序
		Arrays.sort(b);
		//3、将数组a的元素依次对应和数组b的左右两边依次比较,
		//记录左边开始数组比较不对应的编号left、记录右边开始两个数值比较不相同的编号right
		int left=0;//左边第一个元素
		int right=len-1;//右边第一个元素
		while(a[left]==b[left])
		if(left<len)left++;//记录左边不相等的元素
		
		while(a[right]==b[right])
	     right--;//记录右边不相等时的元素的编号
		
		
		boolean flag=true;//默认返回true
		//输出[left,right]就是那一段序列
		//看是否满足交叉相等的规律
		for(int i=0;i<right-left;i++) {
			//如果不满足交叉相等的规律
			if(a[left+i]!=b[right-i])
				flag=false;
		}
		//如果满足规律输出yes,否则no
		if(flag==true)
			System.out.println("yes");
		else
			System.out.println("no");
			
		}

	}

}

7.求数列的和

题目描述:

数列的定义如下: 数列的第一项为n,以后各项为前一项的平方根,求数列的前m项的和。

输入

81 4
2 2

输入数据有多组,每组占一行,由两个整数n(n<10000)和m(m<1000)组成,n和m的含义如前所述。

输出

94.73
3.41

对于每组输入数据,输出该数列的和,每个测试实例占一行,要求精度保留2位小数。


import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//思路:
		/*
		 * 1定义一个数组长度为m的数组
		 * 2将第一个数n进行循环开平方保存在数组里面
		 * 3将数组求和
		 */
		//从键盘接受数据
		Scanner sc=new Scanner(System.in);
		while(sc.hasNext()) {//循环输入
			
		double n=sc.nextInt();//数列第一个数
		int m=sc.nextInt();//数列的长度
		double[] arr=new double[m];//定义一个长度为m的数组保存数据
		
		double num=0;//累加
		arr[0]=n;
		for(int i=1;i<m;i++) {
			arr[i]=Math.sqrt(n);//将第一个数进行开方,存放到数组当中
			n=Math.sqrt(n);
		}
		for(int i=0;i<m;i++) {
			//System.out.println(arr[i]);
			num+=arr[i];
			
		}
		//%.2f %. 表示 小数点前任意位数   2 表示两位小数 格式后的结果为f 表示浮点型
		System.out.println(String.format("%.2f",num));
		
		
		
		
		}
	}

}

8.找水仙花数

/*
     * 找水仙花数
     * 水仙花数”是指一个三位数,它的各位数字的立方和等于其本身,比如:153=1^3+5^3+3^3
     * 思路:
     * 1、定义一个长度(n-m+1)数组
     * 2、取出一个数,并求出百位、十位、个位
     * 3、判断是否满足要求存在一个新数组里面,不满足则进行找下一个
     */

package com.test;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main2 {
	/*
	 * 找水仙花数
	 * 水仙花数”是指一个三位数,它的各位数字的立方和等于其本身,比如:153=1^3+5^3+3^3
	 * 思路:
	 * 1、定义一个长度(n-m+1)数组
	 * 2、取出一个数,并求出百位、十位、个位
	 * 3、判断是否满足要求存在一个新数组里面,不满足则进行找下一个
	 */

	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		
		while(sc.hasNext()){
//			String s=sc.nextLine();//读取控制台的一行数据
//			String[] array=s.split(" ");//根据空格把数据拆分
			int m=sc.nextInt();//区间第一个数
			int n=sc.nextInt();//区间最后一个数
			//定义一个长度为n-m+1的数组
			int[] arr= new int[20];
			boolean flag=false;
			int j=0;
			for(int i=m;i<n;i++){
				//if(i>=m&&i<=n) {
					int a=i/100;//百位
					int b=(i%100)/10;//十位
					int c=(i%100)%10;//个位
					if((a*a*a+b*b*b+c*c*c)==(a*100+b*10+c))
					{   
							arr[j]=a*100+b*10+c;
							j++;
							flag=true;
						}
						
					}

			if(flag==true) {
				for(int i=0;i<j;i++)
				System.out.print(arr[i]+" ");
			}
			else
				System.out.print("no");
			//}
			
			
		}
	

	}

}

9.大小写转换 II

描述

将一个字符串中的小写字母转换为大写字母。忽略其他不是字母的字符。

样例

给出 "abc", 返回 "ABC".

给出 "aBc", 返回 "ABC".

给出 "abC12", 返回 "ABC12".

思路:

1、定义一个空字符串Newstr

2、取出输入的字符串的每一个元素,判断是否是小写字母

3、如果是小写字母则变成大写并加到Newstr上,如果不是则直接加到Newstr字符串上

public class Solution {
    /**
     * @param str: A string
     * @return: A string
     */
    public String lowercaseToUppercase2(String str) {
        // write your code here
        String newStr ="";//定义一个空字符串
        for (int i = 0; i < str.length(); i++){//遍历传进来的字符串
            char ch = str.charAt(i);//charAt(i)方法返回第i个元素
            if (Character.isLowerCase(ch)){//如果这个元素是小写的
                ch = Character.toUpperCase(ch);//则输出大写
            }
            newStr += ch;//将转换的字符串加一起输出
        }
        return newStr;
    }
}

10.找水仙花数II

描述

水仙花数的定义是,这个数等于他每一位上数的幂次之和 见维基百科的定义

比如一个3位的十进制整数153就是一个水仙花数。因为 153 = 13 + 53 + 33。

而一个4位的十进制数1634也是一个水仙花数,因为 1634 = 14 + 64 + 34 + 44。

给出n,找到所有的n位十进制水仙花数。

你可以认为n小于8。

样例

比如 n = 1, 所有水仙花数为:[0,1,2,3,4,5,6,7,8,9]
而对于 n = 2, 则没有2位的水仙花数,返回 []

思路

  1. 1位数范围是[0,9] ; 2位数的范围是[10,99] ;3位数的范围是[100,999]...n位数的范围是[10^(n-1),(10^n)-1]
  2. 所以做一个循环,1=<n<=8,时,查找每一个范围,是否满足水仙花数的规律,满足则放到数组中
  3. 定义一个pow(m,n)函数,作用返回m的n次方,其中m可以是一个数的个位、十位、百位;
  4. 定义一个数组装满足水仙花规律的数
package com.test;

import java.util.ArrayList;

public class Solution {

	/*
	 * @param n: The number of digits.
	 * 
	 * @return: All narcissistic numbers with n digits.
	 */
	public ArrayList<Integer> getNarcissisticNumbers(int n) {
		// write your code here
		/*
		 * 找水仙花数 
		 * 1.定义一个数组 
		 * 2.定义一个pow(m,n)函数,返回m的n次方的结果 
		 * 3.n位数的范围区间内循环,在里面找满足水仙花数,满足结果则返回
		 */
		ArrayList<Integer> result = new ArrayList<Integer>();
		if(n==1)
		{
			for(int i=0;i<10;i++){
				result.add(i);
			}
			return result;
		}
			
		for (int i = pow(10, n - 1); i <= (pow(10, n) - 1); i++) {// n位数的区间
			int num = i;
			int temp = 0;
			for (int j = 0; j < n; j++) {
				temp += pow((num % 10), n);// 计算是否满足水仙花数的规律
				num = num / 10;// 拿出个位、十位、..
			}
			if (temp == i) {
				result.add(temp);
			}

		}
		return result;
	}

	public final int pow(int m, int n) {
		int val = 1;
		for (int i = 1; i <= n; ++i)
			val *= m;// 累乘的结果
		return val;
	}
}

11.在链表中找节点

描述

在链表中找值为 value 的节点,如果没有的话,返回空。

样例

给出 1->2->3 和 value = 3, 返回最后一个节点 last node.

给出 1->2->3 和 value = 4, 返回空。


public class Solution {
    /*
     * @param head: the head of linked list.
     * @param val: An integer.
     * @return: a linked node or null.
     */
    public ListNode findNode(ListNode head, int val) {
        // write your code here
        while(head!=null){
            if(head.val==val){//如果值与当前相等,则返回此时的节点
                return head;
            }
            head=head.next;//如果不符合,继续往下走
        }
        return head;
    }
}

12.链表的中点

描述

找链表的中点。

样例

链表 1->2->3 的中点是 2

链表 1->2 的中点是 1

挑战

如果链表是一个数据流,你可以不重新遍历链表的情况下得到中点么?

思路:遍历链表得到链表长度,中点的位置是(链表长度-1)/2的下标位置,返回这个节点。

public class Solution {
    /**
     * @param head: the head of linked list.
     * @return: a middle node of the linked list
     */
    public ListNode middleNode(ListNode head) {
        // 新建一个ListNode对象,为头结点
        ListNode ln =head;
        int i=0;
        while(head!=null){
            head=head.next;//遍历链表,直至到尾部,得出链表的长度
            i++;
        }
        
        for(int j=0;j<(i-1)/2;j++){//找到中间那个数
            ln=ln.next;
        }
        return ln;
        
    }
}

13.转换字符串到整数(容易版)

描述

Given a string, convert it to an integer. You may assume the string is a valid integer number that can be presented by a signed 32bit integer (-231 ~ 231-1).

样例

给出 "123", 返回 123.

public class Solution {
    /**
     * @param str: A string
     * @return: An integer
     */
    public int stringToInteger(String str) {
        // write your code here
        //valueOf是Integer类的一个静态方法,
        //它是把一个string参数转换为Integer类型
        //那么经过Integer.valueOf("345")转换,345就是一个Integer类型了
        return Integer.valueOf(str);
    }
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值