算法在线刷题记录
- 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
思路: 将改整数转换成为二进制的字符数组,然后对数组进行遍历判断;
代码实现:
public class Solution {
public int NumberOf1(int n) {
String string = Integer.toBinaryString(n); //转换成为二进制字符串
char[] c = string.toCharArray(); // 字符串转换成为二进制字符数组
int count = 0;
for (int i=0; i<c.length; i++){
// 遍历判断
if(c[i]=='1'){
count ++;
}
}
return count;
}
}
- 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
**思路:**使用两个数组将待处理数组中的奇数和偶数分离出来,分别计数,然后在按题目要求将这两个数组中的数添加到原先的数组当中去。
代码实现:
public class Solution {
public void reOrderArray(int [] array) {
int[] odd = new int[array.length]; // 存放奇数的数组
int[] even = new int[array.length]; // 存放偶数的数组
int oddcount = 0;
int evencount = 0;
for (int i=0;i<array.length;i++){
if(array[i]%2!=0){
odd[oddcount++] = array[i];
continue;
}
even[evencount++] = array[i];
}
for(int emp=0; emp<oddcount; emp++){
array[emp] = odd[emp];
}
for(int emp=0; emp<evencount;emp++){
array[oddcount+emp] = even[emp];
}
}
}
- 输入一个链表,输出该链表中倒数第k个结点。
思路: 利用链表两段位置是对称的,先设置一个节点p并向后移动k个结点,这时候p距离最后一个节点与倒数第k个结点距离头结点的距离是一样的。
代码实现:
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
if(k<=0) return null;
ListNode p1 = head;
ListNode p2 = head;
//p2向前移动k个节点
for(int i=0;i<k-1;i++) {
if(p2==null) return null;
p2 = p2.next;
}
if(p2==null) return null;
while(p2.next!=null) {
// p2向后移动到最后一个节点的次数与头结点向后移动的次数相等时,p1就是倒数第k个结点
p1=p1.next;
p2=p2.next;
}
return p1;
}
}
- 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
思路: 基于这样一个特殊的二维数组的查找问题,关键点就是寻找最佳的查找路径。把二维数组抽象成为一个正方形,则从右上角开始查找是最佳的。
代码实现: 注意获取行数和列数的方法
public class Solution {
public boolean Find(int target, int [][] array) {
int hang = array.length;
int lie = array[0].length;
int cow = 0;
int row = lie-1;
while(cow<hang&&row>=0){
int value = array[cow][row];
if(target>value){
cow++;
}else if(target<value){
row--;
}else{
return true;
}
}
return false;
}
}
- 输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
思路: 利用stack的先进后出的特点,先将原先链表中的数值次序的压入栈中,然后在把出栈的数值一个个添加到一个数组当中
代码实现:
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
Stack<Integer> stack = new Stack<>();
while (listNode != null) {
stack.push(listNode.val);
listNode = listNode.next;
}
ArrayList<Integer> list = new ArrayList<>();
while (!stack.isEmpty()) {
list.add(stack.pop());
}
return list;
}
}
递归代码实现
public class Solution {
ArrayList<Integer> arrayList=new ArrayList<Integer>();
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
if(listNode!=null){
this.printListFromTailToHead(listNode.next);
arrayList.add(listNode.val);
}
return arrayList;
}
}
- 用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
思路: 抓住两种数据结构的特点,先用一个栈s1来实现队列的入队(入栈)操作,当要出队的时候,将栈s1出栈到栈s2入栈,然后依靠s2的出栈实现队列先进先出的出队,完成之后再把s2中的数值出栈到s1中。
代码实现:
import java.util.Stack;
public class Solution {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
public void push(int node) {
stack1.push(node);
}
public int pop() {
for(int i=stack1.size()-1;i>=0; i--){
stack2.push(stack1.get(i));
}
stack1.remove(0);
return stack2.pop();
}
}
- 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)。
思路: 循环实现累加和递归实现
代码实现:
public class Solution {
public int Fibonacci(int n) {
if(n==0){
return 0;
}
if(n==1){
return 1;
}
int front = 0;
int rear = 1;
int temp = 0;
while(!((n-1)==0)){
temp = front + rear;
front = rear;
rear = temp;
n--;
}
return temp;
}
}
public int Fibonacci(int n){
if (n==0){
return 0;
}
if (n==1) {
return 1;
}
return Fibonacci(n-1)+Fibonacci(n-2);
}
- 操作给定的二叉树,将其变换为源二叉树的镜像。
思路: 递归的方法实现到达一个节点的时候,交换左右连个孩子的位置。
代码实现:
public class Solution {
public void Mirror(TreeNode root) {
if(root==null){
return;
}
if(root.left==null && root.right==null){
return;
}
if (root.left==null) {
// 如果左孩子为空
root.left = root.right;
root.right = null;
Mirror(root.left); // 递归处理交换后的左子树
return;
}
if (root.right==null) {
// 如果右孩子为空
root.right = root.left;
root.left = null;
Mirror(root.right); // 递归处理交换后的右子树
return;
}
TreeNode temp = new TreeNode(0); // 如果左右孩子都不为空
temp = root.left;
root.left = root.right;
root.right = temp;
Mirror(root.left); // 递归处理左子树
Mirror(root.right); // 递归处理右子树
}
}
- 给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],…,k[m]。请问k[0]xk[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
思路: 首先我考虑的是先实现一个整数分成两个整数求得他们乘积的最大值,于是设置a,b两个变量,他们相加为这个整数。于是通过遍历的方法得到a,b这存在的组合,然后返回最大值。但是题目给出的是将这个整数分成至少两段的最大值,这里便是用了递归的思想:先分成两段,然后将其中的一段再分成两段,求得最大值返回。具体有点绕,直接上代码。
代码实现:
class Solution {
public static int cutRope(int target) {
if (target<2) {
return target;
}
int a = 1; // 从1开始保证2,3至少有两段
int b = 0;
int ab = 0;
int max = 0;
while(a<=target/2){
// a开始遍历
if (target-a>4) {
// b的值大于才有必要递归分割(分割之后的乘积才比原来大)
b = cutRope(target - a); // 会返回b分割之后的乘积最大值
}else {
b = target-a;
}
// System.out.printf("a==%d,b==%d\n",a,b); 输出测试一下
ab = a * b;
// System.out.println(ab);
if(ab>max){
max = ab;
// System.out.println("max=="+max);
}
a ++;
}
return max;
}
}
- 地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
思路: 首先这道题目之前自己做了很久,因为可以使用某种公式可以按照不同的情况直接套用,之后多次地测试发现并不可行。看了B站的视频——【剑指offer】面试题13-机器人的运动范围 之后才意识到这是考察一个深度优先遍历的知识点,于是又去B站学习了一下深度优先遍历的视频,最后才理解了这倒算法题目。看着注释和代码读者应该不难理解。
代码实现:
import java.util.Queue;
import java.util.LinkedList;
public class Solution {
public int movingCount(int k, int m, int n)
{
// 定义这两个数组代表着机器人周围(上下左右)的点
int[] dx = {
0, 0, 1, -1};
int[] dy = {
1, -1, 0, 0};
// 这个队列用来存放可以到达的格子
Queue<int[]> queue = new LinkedList<>();
// 将起点添加到这个队列当中
queue.offer(new int[] {
0,0});
// 记录访问过的格子
boolean[][] visited = new boolean[m][n];
if (k > 0){
visited[0][0] = true;
}
// 对每个能到达的格子的周围格子进行遍历
while(!queue.isEmpty()){
int [] cur = queue.poll();
// 周围格子遍历
for (int i = 0; i < 4; i++){
int x = cur[0] + dx[i];
int y = cur[1] + dy[i];
// 超出了参数限制
if (x < 0 || x >= m || y < 0 || y >= n) continue;
// 计算他们的数位之和并判断
int value = solve(x) + solve(y);
if (value > k || visited[x][y]) continue;
visited[x][y] = true;
queue.offer(new int[] {
x, y});
}
}
// 计算可以到达的格子个数
int res = 0;
for (int i = 0; i< m; i++)
for (int j = 0; j < n; j++){
if (visited[i][j]) res++;
}
return res;
}
// 计算数位和
private int solve(int num) {
int res = 0;
while (num > 0){
res += num % 10;
num /= 10;
}
return res;
}
}
- 从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
思路: 每扫描一个节点就先把他的左右孩子放在一个队列当中,当这个节点和他的兄弟遍历完成以后,从这个队列中读取下一层的结点,每遍历一次,就把它从队列中剔除。当这个队列为空的时候就完成了遍历。需要用到的数据结构有队列、链表
代码实现:
public static ArrayList<ArrayList<Integer>> printNode(TreeNode pNode){
// 存放每层结点的链表
ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>();
// 将需要遍历那层的结点存放在这个队列当中
Queue<TreeNode> readyNode = new LinkedList<TreeNode>();
TreeNode currentNode = new TreeNode();
readyNode.add(pRoot);
while(!readyNode.isEmpty()){
ArrayList<Integer> currentList = new ArrayList<Integer>();
// 获得当层节点的数量
int size = readyNode.size();
// 开始遍历当前层
for(int i=0; i<size; i++){
currentNode = readyNode.remove();
currentList.add(currentNode.getVal());
// 每个结点的下一层存放到准备结点中
if (currentNode.getLeft()!=null) {
readyNode.add(currentNode.getLeft());
}
if (currentNode.getRight()!=null) {
readyNode.add(currentNode.getRight());
}
}
list.add(currentList);
}
return list;
}
nt i=0; i<size; i++){
currentNode = readyNode.remove();
currentList.add(currentNode.getVal());
// 每个结点的下一层存放到准备结点中
if (currentNode.getLeft()!=null) {
readyNode.add(currentNode.getLeft());
}
if (currentNode.getRight()!=null) {
readyNode.add(currentNode.getRight());
}
}
list.add(currentList);
}
return list;
}