编程题——2

一、数独问题

输入9行,每行为空格隔开的9个数字,为0的地方就是需要填充的。
输出九行,每行九个空格隔开的数字,为解出的答案。

解题思路:

分析:数独就是9行9列的数组,满足每一行、每一列、每一个粗线宫内的数字均含1-9,不重复。(图四为粗线宫)

解题:DFS深度填数检测+回溯法

     1. 设置标记位。将有提示数的位置标记为true,需要填数的位置标记为false。

     2. 循环遍历数组标记为false的地方,也就是需要填数的地方。

           如果当前为0,即a[i][j]==0,判断当前所在的九宫格,然后从数字1-9依次检测是否在行、列、宫中唯一

                     ——满足唯一的话,则把数字赋值给a[i][j]=l+1;然后继续深度遍历为true的话就返回true,否则回溯a[i][j]==0

                     ——不满足唯一则判断下一个数字,直到1-9都判断不满足则返回false,会回溯到上一层

       如果当前没有0,说明都已经填满且符合唯一条件,则返回true;结束

总结源于:https://blog.csdn.net/hll174/article/details/51090461

二 旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

解题思路:二分法

import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        int low=0;
        int high=array.length-1;
        while(low<high){
            int mid=low+(high-low)/2;
            if(array[mid]>array[high])
                low=mid+1;
            else if(array[mid]==array[high])
                high=high-1;
            else high=mid;
        }
        return array[low];
    
    }
}

三 斐波那契数列

求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。
n<=39

解题思路:用递归栈要溢出,故采用迭代;

public class Solution {
    public int Fibonacci(int n) {
        int prePreNum=0;
        int preNum=1;
        int result=0;
        if(n==0)
            return 0;
        if(n==1)
            return 1;
        for(int i=2;i<=n;i++){
            result=prePreNum+preNum;
            prePreNum=preNum;
            preNum=result;
        }
        return result;
    }   

    }

三 青蛙跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级。
求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

解题思路:对于第n个台阶来说,只能从n-1或者n-2的台阶跳上来

F(n) = F(n-1) + F(n-2)

斐波拉契数序列,初始条件

n=1:只能一种方法

n=2:两种

public class Solution {
    public int JumpFloor(int target) {
        if(target<=0)
            return 0;
        else if(target==1)
            return 1;
        else if(target==2)
            return 2;
        else 
            return JumpFloor(target-1)+JumpFloor(target-2);

    }
}

四 变态跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。
求该青蛙跳上一个n级的台阶总共有多少种跳法

解题思路:

因为n级台阶,第一步有n种跳法:跳1级、跳2级、到跳n级
跳1级,剩下n-1级,则剩下跳法是f(n-1)
跳2级,剩下n-2级,则剩下跳法是f(n-2)
所以f(n)=f(n-1)+f(n-2)+...+f(1)
因为f(n-1)=f(n-2)+f(n-3)+...+f(1)

所以f(n)=2*f(n-1)

public class Solution {
    public int JumpFloorII(int target) {
        if(target<=0)
            return 0;
        else if(target==1)
            return 1;
        else if(target==2)
            return 2;
        else 
            return 2*JumpFloorII(target-1);
    }
}

五 矩形覆盖

我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。
请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

解题思路:

依旧是斐波那契数列:

public class Solution {
    public int RectCover(int target) {
        if(target<=0)
            return 0;
        if(target*2==2)
            return 1;
        if(target*2==4)
            return 2;
        else 
            return RectCover(target-1)+RectCover(target-2);

    }
}

六 二进制中1的个数

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

解法1:(用java的API,此题显然不是此考意,但是也算是一个解法)

public class Solution {
    public int NumberOf1(int n) {
        return Integer.toBinaryString(n).replaceAll("0","").length();

    }
}

解法二:

如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。

举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。

public class Solution {
    public int NumberOf1(int n) {
        int count=0;
        while(n!=0){
            count++;
            n=n&(n-1);
        }
        return count;

    }
}

七 数值的整数次方

给定一个double类型的浮点数base和int类型的整数exponent。
求base的exponent次方。

解题思路:注意考虑指数为负数的情况。

public class Solution {
    public double Power(double base, int exponent) {
        double result=1;
        for(int i=0;i<Math.abs(exponent);i++){
            result*=base;
        }
        if(exponent<0)
            result=1/result;
        return result;
  }
}

八 调整数组顺序使奇数位于偶数前面

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,
所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

解题思路:

-相对位置不变——稳定性(插入排序、冒泡排序、归并排序)

-类似于冒泡排序

public class Solution {
    public void reOrderArray(int [] array) {
        for(int i=0;i<array.length-1;i++)
            for(int j=0;j<array.length-i-1;j++){
                if(array[j]%2==0 && array[j+1]%2==1){
                int temp=array[j];
                array[j]=array[j+1];
                array[j+1]=temp;
                }
            }
    }
}

八 .链表中倒数第k个结点

输入一个链表,输出该链表中倒数第k个结点

解题思路:

两个指针,p指针和pre指针都指向头结点,然后再让p指针走(k-1)步,到达第k个节点。然后两个指针同时往后移动,当p结点到达末尾的时候,pre结点所在位置就是倒数第k个节点了。

public class Solution {
    public ListNode FindKthToTail(ListNode head,int k) {
        ListNode p=null, pre=null;
        p=head;
        pre=head;
        int a=k;   //记录k的值
        int count=0;  //记录节点的个数
        //指针p先跑,并且记录节点数,当p指针跑了k-1个节点后,pre指针开始跑,
        //当p指针跑到最后时,pre所指指针就是倒数第k个节点
        while(p!=null){
            p=p.next;
            count++;
            if(k<1){
                pre=pre.next;
            }
            k--;
        }
        //如果节点个数小于所求的倒数第k个节点,则返回空
        if(count<a)
            return null;
        return pre;

    }
}

九. 反转链表

输入一个链表,反转链表后,输出新链表的表头。
public class Solution {
    public ListNode ReverseList(ListNode head) {
       
        if(head==null)
            return null;
        //head为当前节点,如果当前节点为空的话,那就什么也不做,直接返回null;
        ListNode pre = null;
        ListNode next = null;
        //当前节点是head,pre为当前节点的前一节点,next为当前节点的下一节点
        //需要pre和next的目的是让当前节点从pre->head->next1->next2变成pre<-head next1->next2
        //即pre让节点可以反转所指方向,但反转之后如果不用next节点保存next1节点的话,此单链表就此断开了
        //所以需要用到pre和next两个节点
        //1->2->3->4->5
        //1<-2<-3 4->5
        while(head!=null){
            //做循环,如果当前节点不为空的话,始终执行此循环,此循环的目的就是让当前节点从指向next到指向pre
            //如此就可以做到反转链表的效果
            //先用next保存head的下一个节点的信息,保证单链表不会因为失去head节点的原next节点而就此断裂
            next = head.next;
            //保存完next,就可以让head从指向next变成指向pre了,代码如下
            head.next = pre;
            //head指向pre后,就继续依次反转下一个节点
            //让pre,head,next依次向后移动一个节点,继续下一次的指针反转
            pre = head;
            head = next;
        }
        //如果head为null的时候,pre就为最后一个节点了,但是链表已经反转完毕,pre就是反转后链表的第一个节点
        //直接输出pre就是我们想要得到的反转后的链表
        return pre;
    }
}

十 合并两个排序的链表

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
        if(list1==null)
            return list2;
        if(list2==null)
            return list1;
        ListNode temp=null;
        if(list1.val<list2.val){
            temp=list1;
            temp.next=Merge(list1.next, list2);
        }
        else {
            temp=list2;
            temp.next=Merge(list1, list2.next);
        }
        return temp;
            
    }
}

十一 判断字符串是否为回文串

可以删除一个字符,判断是否能构成回文字符串。
package train;

import java.util.Scanner;

public class HuiWeiChuan {

	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		String str=scan.nextLine();
	    System.out.println(validPalindrome(str));
		scan.close();

	}
	
	public static boolean validPalindrome(String s) {
	    int i = -1, j = s.length();
	    while (++i < --j) {
	        if (s.charAt(i) != s.charAt(j)) {
	            return isHuiWei(s, i, j - 1) || isHuiWei(s, i + 1, j);
	        }
	    }
	    return true;
	}

	public static boolean isHuiWei(String str, int i, int j) {
		while(i<j) {
			if(str.charAt(i++)!=str.charAt(j--)) {
				return false;
			}
		}
		return true;
	}

}

十二 顺时针打印矩阵

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,
例如,如果输入如下4 X 4矩阵: 1 2 3 4 
                            5 6 7 8 
                            9 10 11 12 
                            13 14 15 16 
则依次打印出数字
1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

解题思路:1 循环打印   2 顺时针打印一圈

	//由于题目是以从外圈到内圈的顺序依次打印,在矩阵中标注一圈作为分析的目标。
	//设矩阵的宽度为cols,而其高度为rows。
	//选取左上角坐标为(startX, startY),右下角坐标为(endX, endY)的一个圈来分析。
	//由于endX和endY可以根据startX、startY以及columns、rows来求得,因此此时我们只需要引入startX和startY两个变量。我们可以想象有一个循环,在每一次循环里我们从(startX, startY)出发按照顺时针打印数字。
        //接着分析这个循环结束的条件。
	//对一个5×5的矩阵而言,最后一圈只有一个数字,对应的坐标为(2, 2)。
	//我们发现5 > 2 * 2。对一个6×6的矩阵而言,最后一圈有四个数字,对应的坐标仍然为(2, 2)。我们发现6 > 2 * 2依然成立。
	//于是我们可以得出,让循环继续的条件是“cols > startX * 2 && rows > startY * 2”。
	public static ArrayList<Integer> printMatrix(int[][] matrix){
		//用一个线性表存放顺时针打印的结果
		ArrayList<Integer> li=new ArrayList<Integer>();
		int rows=matrix.length;
		int columns=matrix[0].length;
		int start = 0;
		while(rows>start*2 && columns > start*2) {
			printMatrixInCircle(matrix, rows, columns, start,li);
			start++;
		}
		return li;
	}
//打印一圈
	public static  void printMatrixInCircle(int[][] matrix, int rows,int columns, int start, ArrayList<Integer> list){
		//从左到右打印一行
		for(int i=start;i<columns-start;i++) {
			list.add(matrix[start][i]);
		}
		//从上到下打印一列
		for(int j=start+1;j<rows-start;j++) {
			list.add(matrix[j][columns-start-1]);
		}
		//从右到左打印一列
		//列要小于圈开始的列数,行要小于圈开始的行数
		for(int m=columns-start-2;m>=start && rows-start-1>start;m--) {
			list.add(matrix[rows-start-1][m]);
		}
		//从下到上打印一列
		//行要小于圈开始的行数+1,列要小于圈开始的列数
		for(int n=rows-start-2;n>=start+1 && columns-start-1>start;n--) {
			list.add(matrix[n][start]);
		}
	}
	

十三 滑动窗口的最大值

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。
如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,
他们的最大值分别为{4,4,6,6,6,5}; 
针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: 
{[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, 
{2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, 
{2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
package train;

import java.util.ArrayList;


public class MaxWindows {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		int windowSize=3;
		int[] array= {2,3,4,2,6,2,5,1};
		
	    System.out.println(maxInWindows(array, windowSize));
		
	}
	
	public static ArrayList<Integer> maxInWindows(int[] a, int size){
		ArrayList<Integer> list=new ArrayList<Integer>();
		
		if(size==0 || a.length<size)
			System.out.println("输入有误!");
		for(int i=0;i<=a.length-size;i++) {
			int max=a[i];
			for(int j=i+1;j<i+size;j++) {
				if(a[j]>max) {
					max=a[j];
				}
			}
			list.add(max);
		}
		return list;
	}
}

十四. 机器人的运动范围

地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,
每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。
例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。
但是,它不能进入方格(35,38),因为3+5+3+8 = 19。
请问该机器人能够达到多少个格子

解题思路:递归,dfs

import java.util.Scanner;

public class MovingCount {

	public static void main(String[] args) {
		Scanner scanner=new Scanner(System.in);
		int k=scanner.nextInt();
		int rows=scanner.nextInt();
		int columns=scanner.nextInt();
		System.out.println(movingCount(k, rows, columns));
		scanner.close();

	}
	
	public static int movingCount(int k, int rows, int columns) {
		int[][] flag=new int[rows][columns];
		return moving(k, rows, columns, flag, 0, 0);
		
	}
	//思路:dfs,搜索四个方向,用flag记录该方格是否被搜索过
	public static int moving(int k, int rows, int columns, int[][] flag, int startX, int startY) {
		//出口:
		//1.不满足边界条件
		//2.已经遍历过
		//3.位数和大于阈值
		if(k<=0 || startX>=rows || startX<0 || startY> columns || startY<0 || (flag[startX][startY]==1) || (sumDig(startX) + sumDig(startY)>k))
			return 0;
		flag[startX][startY]=1;	
		return moving(k, rows, columns, flag, startX-1, startY)
				+moving(k, rows, columns, flag, startX+1, startY)
				+moving(k, rows, columns, flag, startX, startY-1)
				+moving(k, rows, columns, flag, startX, startY+1)
				+1;
	}
	public static int sumDig(int n) {
		int sum=0;
		if(n>=10) {
			sum += n%10;
			sum += sumDig(n/10);
		}
		else sum += n;
		return sum;
	}

}

十五 包含min函数的栈

定义栈的数据结构,
请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

解题思路:

用一个栈data保存数据,用另外一个栈min保存依次入栈最小的数

比如,data中依次入栈,543, 8, 10, 11, 12, 1

       则min依次入栈,543,no,no, no, no, 1

每次入栈的时候,如果入栈的元素比min中的栈顶元素小或等于则入栈,否则不入栈。(no代表此次不入栈)

压栈:压的时候,如果 1.栈data的压入比栈min的压入大,min栈不压
                   2.小于等于,两个栈同时压入
出栈:如果,两个栈的栈顶元素不等,栈data出,栈min不出。
import java.util.Stack;

public class Solution {
    Stack<Integer> data=new Stack<Integer>();
    Stack<Integer> min=new Stack<Integer>();
    Integer temp=null;  
    public void push(int node) {
        if(temp!=null){
            if(node<=temp){
                temp=node;
                min.push(node);
            }
            data.push(node);
        }
        else {
            temp=node;
            data.push(node);
            min.push(node);
        }
    }
    
    public void pop() {
        int num=data.pop();
        int num2=min.pop();
        if(num!=num2){
            min.push(num2);
        }
    }
    
    public int top() {
        return data.peek();
    }
    
    public int min() {
        return min.peek();
        
    }
}

猜你喜欢

转载自blog.csdn.net/Ella7/article/details/81388597