不要急,不要急,马上好^_^...

每日算法


Leetcode

两数相加(2021-11-26)

class Solution {
    public int[] twoSum(int[] nums, int target) {
        //使用hashmap进行两数相加
        /**
            思想:主要就是map里面的核心方法containsKey,这个方法
            判断这个键是否存在,如果存在,那么就通过map的get方法获
            取值也就是下标,返回,否则就将数据存到map中,进行下一次
            查询判断
         */
         HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
         for(int i =0;i<nums.length;i++){
             if(map.containsKey(target - nums[i])){
                return new int[]{map.get(target-nums[i]),i};
             }
            map.put(nums[i],i);
         }
         return new int[0];
    }
}

整数反转(2021-11-27)

class Solution {
    public int reverse(int x) {
        /**
            可以通过字符串进行,但是如果考虑性能问题
            还是选择对这个整数进行取余的操作
            思路:用取余的方式可以得到尾数,然后将这个
            尾数记录,如果下一次再次进入循环,那么将尾
            数进行移位并且加上取余的数
         */

        //标志位,long类型很重要,最后判断越界异常
         long  n =0;
         while(x !=0){
             //将每次得到的尾数进行记录
             n = n*10 +x %10;
             //每次都会减少一个尾数
             x = x/10;
         }
         //判断是否有越界
         return (int) n == n?(int)n:0;
    }
}

两数相加(2021-11-29)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
 /**
    核心思想:
        首先判断两个链表是否为空以及是否有进位标志,如果有那么就需要进行增加节点操作,
        增加节点首先判断两个链表当前是否有值,如果有则使用当前值,如果没有则使用0当做
        当前值,然后对当前两个链表的值相加,如果有进位那么将进位也一起想加,得到的
        值先进行除以10的操作,主要就是判断当前所得的值是否大于10,如果大于则记录当前
        进位,如果不大于则为0,然后将这个值进行取余操作,存入到链表中,然后更新链表
        指针,进行下一轮扫描执行操作

  */
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        //新建链表
        ListNode l3 = new ListNode(0);
        //建立一个指针操作链表
        ListNode root = l3;
        //进位标志
        int c = 0;
        while(l1!=null||l2!=null||c!=0){
            //记录当前两个链表的值
            int l1val = l1!=null?l1.val:0;
            int l2val = l2!=null?l2.val:0;
            //相加(注意添加进位标志)
            int sumval = l1val + l2val + c;
            //重新计算进位标志
            c = sumval/10;
            //将sumval添加到新建的链表中
            root.next = new ListNode(sumval%10);
            root = root.next;
            //然后判断链表是否为空,进行下一次循环
            if(l1!=null) l1 = l1.next;
            if(l2!=null) l2 = l2.next;
        }
        //返回结果
        return l3.next;
    }
}

无重复字符串的最长子串(2021-12-02)

class Solution {
    public int lengthOfLongestSubstring(String s) {
        /**
        核心思想:使用hashmap来解决此问题
            主要是将字符串存到map中,在扫描的过程中判断每次存的字符串是否重复,
            如果重复就将上一次出现这个值得位置+1,这样就能从新的位置开始扫描,

         */

        //创建一个新数组
         HashMap<Character,Integer> map = new HashMap<>();
        //初始化最大长度
        int max = 0;
        //初始化开始扫描的位置
        int start = 0;

        //通过循环将数据添加进map中,并且进行扫描
        for(int i = 0;i<s.length();i++){
            //将插入的值记录
            char c = s.charAt(i);
            //首先判断map中是否存在要插入的值
            if(map.containsKey(c)){
                //如果存在,那么就需要更新开始扫描的位置
                //将开始位置更新为当前重复元素的上一次出现位置的下一个位置
                start = Math.max(start,map.get(c)+1);
            }
            //更新max的值
            max = Math.max(max,i-start+1);
            //将数据添加进map中,注意这里如果key重复了,那么就会用最新的值覆盖之前的值
            map.put(c,i);
        }
        return max;
    }
}

用两个栈来实现队列(2021-12-8)

class CQueue {

    //初始化两个栈
    Stack<Integer> stack1;
    Stack<Integer> stack2;

    public CQueue() {
        stack1 = new Stack<>();
        stack2 = new Stack<>();
    }

    /**
    阐述一下思想:
        使用两个栈实现队列,首先要知道的是栈是先进后出,而队列是先进先出的
        其次就是队列是队头移除,队尾插入
        
    如何实现?
        在入队的时候,就是普通的入栈操作,但是出队就需要将栈的顺序反过来,
        意思就是比如现在添加了几个元素1,2,3,4,5,在栈中的顺序是5,4,3,2,1
        现在进行队列的删除操作,也就是将对头的1进行移除,那么此时就需要
        借助第二个栈,将栈1的数据都弹出存到栈2,这样顺序就变成了1,2,3,4,5
        移除操作就是删除栈2的栈顶元素

     */
    
    public void appendTail(int value) {
        stack1.push(value);
    }
    
    public int deleteHead() {
        /**
            删除元素首先得判断栈2是否有元素,如果有就直接弹出
            如果没有就需要将栈1的数据压到栈2,如果栈1的数据是
            空,就返回-1,意思就是没有数据
         */
         if(!stack2.isEmpty()){
             return stack2.pop();
         }
         while(!stack1.isEmpty()){
             stack2.push(stack1.pop());
         }

         return stack2.isEmpty()?-1:stack2.pop();


    }
}

/**
 * Your CQueue object will be instantiated and called as such:
 * CQueue obj = new CQueue();
 * obj.appendTail(value);
 * int param_2 = obj.deleteHead();
 */

包含min函数的栈(2021-12-8)

class MinStack {

    /**
        思路:
            因为栈的底层数据结构可以是数组,也可以是链表,或者是其他的
            这里因为有最小函数的出现,所以采用链表比较好,因为在链表中
            可以开辟空间存储头部节点以及最小值节点
    
     */
     
     //初始化一个头结点
    private Node head;

    /** initialize your data structure here. */
    public MinStack() {
        
    }
    
    public void push(int x) {
        //判断头结点是否为空,如果为空就进行初始化
        if(head==null){
            head = new Node(x,x,null);
        }else{
            //不为空,那么就需要比较大小,记录最小值
           head = new Node(x,Math.min(x,head.min),head);
           
        }
    }
    
    public void pop() {
        head = head.next;

    }
    
    public int top() {
        return head.val;

    }
    
    public int min() {
        return head.min;

    }
}

//定义节点信息,包含最小值
class Node{
    int val;
    Node next;
    int min;
    public Node(int val,int min,Node next){
        this.val = val;
        this.next = next;
        this.min = min;
    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.min();
 */

从尾到头打印链表(2021-12-9)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
 /**
    思路:
        1. 本来自己做的话想的是使用栈,然后取出用数组存储,但是这样
        就使用了额外的内存
        2. 借鉴思想,反正都是要循环两次解决问题,为什么要创建额外的
        空间存储呢?直接使用倒序插入数组就好了
 
  */
class Solution {
    public int[] reversePrint(ListNode head) {
        ListNode index = head;
         //记录链表的长度,以便创建新的数组长度来存储链表节点
         int size = 0;
         while(index!=null){
             //遍历链表,记录链表长度
             size++;
             index = index.next;
         }
         int [] array = new int[size];
         for(int i =size-1;i>=0;i--){
             array[i] = head.val;
             head = head.next;
         }
         return array;


    }
}

反转链表(2021-12-13)

使用迭代

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        /**
            使用迭代的方式将链表反转
            主要思想:因为节点连接的都是下一个节点,此时将next节点指向pre节点,即可完成链表反转

         */
        
        //记录前面的节点
        ListNode pre  = null;
        //记录当前节点
        ListNode cur = head;

        //遍历链表,并且将指向后面的节点改成指向前面节点,这样就完成倒序了
        while(cur!=null){
            //记录下一个节点
            ListNode next = cur.next;
            //将节点指向改变
            cur.next = pre;
            //指针更新
            pre = cur;
            cur = next;
        }
        return pre;
    }
}

使用递归

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        /**
            使用递归的方式将链表反转
         */
        
        if(head==null||head.next==null){
            return head;
        }

        ListNode reverse = reverseList(head.next);
        head.next.next = head;
        head.next = null;
        return reverse;
    }
}

替换空格(2021-12-13)

class Solution {
    public String replaceSpace(String s) {
        /**
            因为涉及到String的拼接操作,这里考虑使用Stringbuilder进行操作
            如果判断到是空格,那么就进行替换操作
        
         */

        if(s==null){
            return null;
        }

        //存储字符串
         StringBuilder sb = new StringBuilder();

        for(int i = 0; i<s.length();i++){
            if(" ".equals(String.valueOf(s.charAt(i)))){
                sb.append("%20");
            }else{
                sb.append(s.charAt(i));
            }
        }
        return sb.toString();
    }
}

左旋转字符串(2021-12-13)

/*
	解题思路:主要就是使用substring这个函数进行字符串分割然后拼接
*/

class Solution {
    public String reverseLeftWords(String s, int n) {
        if(s==null)
        return null;
        return s.substring(n)+s.substring(0,n);
    }
}

数组中重复的数据(2021-12-13)

class Solution {
    public int findRepeatNumber(int[] nums) {
        /**
            解题思路:
                (一开始想的就是存储在map或者set里,这样只要检测到有重复的key那么直接,返回当前重复的值即可,但是效率太低了)
                根据大佬的思路,首先创建一个新数组,巧妙运用数组初始化时各个下标对应的值都是0
                因此我们可以通过将数组的值作为新数组的下标进行存储,并且这个下标对应的值+1
                那么下一次再遇到同样的下标,也就是重复的数据,我们可以通过这个下标对应的值
                来判断该数据是否重复(也就是如果此时下标对应的值大于1那么就是重复数据)
         */

         //创建一个新数据
         int [] array = new int[nums.length];

         for(int i =0;i<nums.length;i++){
             array[nums[i]]++;
             //判断如果大于1就是重复数据,直接返回即可
             if(array[nums[i]]>1)
             return nums[i];
         }
         return 0;
    }
}

文章作者: Mr Hou
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Mr Hou !
希望得到你的建议哦
  目录