数据结构与算法的练习日记

数据结构与算法的练习日记



前言:

  1. 1-3
  2. 4-

一、Leetcode


1.leetcode 24 两两交换链表中的节点

题目:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

/**
思路:
*/
class Solution {
    public ListNode swapPairs(ListNode head) {
       if(head==null||head.next==null){
           return head;

       }
       ListNode dummyHead=new ListNode(0);
       dummyHead.next=head;
       ListNode temp=dummyHead;
       while(temp.next!=null && temp.next.next!=null){//能创建出着两个新节点
           ListNode node1=temp.next;
            ListNode node2=temp.next.next;
            temp.next=node2;
            node1.next=node2.next;
            node2.next=node1;
            temp=node1;

       }
       return dummyHead.next;

    }
}

2.leetcode 283 移动零

题目:给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

  • 开始的错误解法:
  • 在这里插入图片描述
class Solution {
    public void moveZeroes(int[] nums) {
        int j=nums.length-1;
        int i=0;
        while(i<j){//双指针
            while(nums[j]==0){
                j--;
            }
            if(nums[i]==0){
                int temp=nums[i];
                nums[i] = nums[j];
                nums[j] = temp;
                j--;
            }
             i++;
        }
    }
}
  • 正确的解法:

class Solution {
    public void moveZeroes(int[] nums) {
        int n = nums.length, left = 0, right = 0;
        while (right < n) {
            if (nums[right] != 0) {//如果右指针不是0;左指针的左边都是非0的;
                swap(nums, left, right);//让0都在左右指针中间
                left++;
            }
            right++;//右指针不断向右移动
        }
    }

    public void swap(int[] nums, int left, int right) {
        int temp = nums[left];
        nums[left] = nums[right];
        nums[right] = temp;
    }
}


3 leetcode 485 最大连续 1 的个数

题目:给定一个二进制数组 nums , 计算其中最大连续 1 的个数。

class Solution {
    public int findMaxConsecutiveOnes(int[] nums) {
        int maxCount =0;
        int count =0;
        int n=nums.length;
        for(int i=0;i<n;i++){
            if(nums[i] == 1) {//如果1,就加;
                count++;
            }else{//如果是0,就清零,比较一次;
                maxCount=Math.max(maxCount,count);
                count=0;
            }
        }
        maxCount=Math.max(maxCount,count);
        return maxCount;


    }
}

4 leetcode 203移除链表元素

题目:给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点

/**
 * 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; }
 * }
 */
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        while(head!=null && head.val==val ){//不能写反
            head=head.next;
        } 
        if(head == null){//然后再判断一下边界
            return head;
        }
        ListNode temp=head;
        
        while(temp.next!=null){
            ListNode tempNext=temp.next;
            if(tempNext.val==val){
                temp.next=tempNext.next;
            }else{
                temp=temp.next;
            }
        }
        return head;
    }
}

5 leetcode 160相交链表

题目:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
         //把所有headA 链表添加 到hashSet 中然后headB中 有则就结束
        Set<ListNode> visited =new HashSet<ListNode>();
        ListNode temp=headA;
        while(temp!=null){
            visited.add(temp);
            temp=temp.next;

        }
        temp=headB;
        while(temp!=null){
            if(visited.contains(temp)){
                return temp;
            
            }
            temp=temp.next;
        }
        return null;
       
        

    }
}


6 leetcode 150. 逆波兰表达式求值

题目:给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。

  • 逆波兰表达式:
    逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。
    平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
    该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
    逆波兰表达式主要有以下两个优点:
    去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
    适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中

/**
适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中
*/
import java.util.Stack;
class Solution {
    public int evalRPN(String[] tokens) {
    Stack<Integer> stack =new Stack<>();
    int length=tokens.length;
    for(int i=0;i<length;i++){
        String token=tokens[i];
            if(isNumber(token)){
                stack.push(Integer.parseInt(token));//String类型转化为Integer
            }else {
                int num2=stack.pop();
                int num1=stack.pop();
                switch (token) {
                    case "+":
                        stack.push(num1 + num2);
                        break;
                    case "-":
                        stack.push(num1 - num2);
                        break;
                    case "*":
                        stack.push(num1 * num2);
                        break;
                    case "/":
                        stack.push(num1 / num2);
                        break;
                    default:
                }   
            }
        }
        return stack.pop();
    }
    public boolean isNumber(String token){
        return !("+".equals(token)||"-".equals(token)||"*".equals(token)||"/".equals(token));
    }
}


7 leetcode 141环形链表(是否有无环)

题目:给你一个链表的头节点 head ,判断链表中是否有环。

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        ListNode temp1=head;
        ListNode temp2=head;
        //判断是否有环,使用快慢指针,空间复杂度最低
        //也可以用hashset法
        //最笨的用两重循环一次比较一个节点前面是否出现
        if(temp1==null){
            return false;
        }
        if(temp2.next==null||temp2.next.next==null){
            return false;
        }
        while(temp2!=null&&temp2.next!=null){//temp2跑得快
            temp1=temp1.next;//先后移后判断
            temp2=temp2.next.next;
            if(temp1==temp2){
                return true;
            }
            
        }
        return false;
    }
}

8 leetcode 9回文数

题目:给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。

回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

例如,121 是回文,而 123 不是。

class Solution {
    public boolean isPalindrome(int x) {
        //转换为字符串(回文字符串),就很简单
        String str1=String.valueOf(x);  //x.toString()
        // String str2=x+"";
        // return str1.equals(str2.reverse());//String 是不可变,没有reverse(),要用StringBuilder来新建字符串
        StringBuilder strbu=new StringBuilder();
        strbu.append(str1);//要这样添加
        return str1.equals(strbu.reverse().toString());
    }
}

9 leetcode

题目:



10 leetcode

题目:



11 leetcode

题目:



12 leetcode

题目:



13 leetcode

题目:



14 leetcode

题目:



二、Acwing


1.Acwing

三、其他练习:

1.用hashSet 判断字符串是否有重复元素;

package Practice;
import java.util.HashSet;
public class CharacterRepeat {


    public static boolean isRepeat(String str){
        int length=str.length();
        for(int i=0;i<length;i++){
            for(int j=i+1;j<length;j++){
                if(str.charAt(i)==str.charAt(j)){
                    return true;
                }
            }
        }
        return false;
    }
    public static boolean isRepeat2(String str){
        int length=str.length();
        HashSet<Character> set=new HashSet<>();
        for(int i=0;i<length;i++){
            if(set.contains(str.charAt(i))){
                return true;
            }else{
                set.add(str.charAt(i));
            }
        }
        return false;
    }


    public static void main(String[] args) {
        boolean result=isRepeat2("abcdefg");
        System.out.println(result);

        boolean result2=isRepeat2("abcdefgabc");
        System.out.println(result2);

    }
}

2.用hashMap 计算一个字符串每种字符有多少个;

package Practice;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class StrCounter {

public static HashMap<Character,Integer> getStrCounter(String str){
    HashMap<Character,Integer>  counter=new HashMap<>();
    int length=str.length();
    for(int i=0;i<length;i++){
        Character c=str.charAt(i);
        if(counter.containsKey(c)){
            Integer count=counter.get(c);
            count++;
            counter.put(c,count);
        }else{
            counter.put(c,1);
        }
    }
    return counter;


}


    public static void main(String[] args) {
        HashMap<Character,Integer> counter=new HashMap<>();
        counter=getStrCounter("abcdefgabcd");
       for(Map.Entry<Character,Integer> entry:counter.entrySet()){
           System.out.println(entry.getKey()+" "+entry.getValue());
       }
    }
}

3.用Stack 反转字符串;

package Practice;

import java.util.Stack;

public class StrReverse {


    public static String reverseStr(String str) {

        Stack<Character> stack = new Stack<>();
        int length = str.length();
        for (int i = 0; i < length; i++) {
            char c = str.charAt(i);
            stack.push(c);
        }
        String newStr = new String();
        while (!stack.empty()) {
           newStr += stack.pop();
        }
        return newStr;
    }






    public static void main(String[] args) {
        String s = reverseStr("abcdefg");

        System.out.print(s);

    }
}


4.反转链表

package Practice;

public class reverseLinkedList {

    /**
     * 反转链表非递归方法:
     * 1.定义三个指针,分别指向当前节点,当前节点的前一个节点,当前节点的后一个节点
     * 2.后一个节点先保存起来当前节点的下一个节点,(让后移知道地方);
     * 3.然后开始反转,当前节点的下一个节点指向pre节点,然后pre节点,和当前节点都向后移动;
     * 4.当前节点指向后一个节点,继续循环,直到当前节点为空;
     * 5.最后返回pre节点;
     *
     * 备注:每次只有一个指针转换,然后两个指针后移(后移到cur和next);
     * @param head
     * @return
     */

    public static ListNode reverseLinkedList(ListNode head) {
        ListNode pre = null;//前一个节点
        ListNode cur = head;//当前节点
        while (cur != null) {
            ListNode next = cur.next;//后一个节点,让下面的后移操作知道地方
            cur.next = pre;//反转
            pre = cur;//后移
            cur = next;//后移
        }
        return pre;
    }


    public static void main(String[] args) {
        ListNode head = new ListNode(1);
        ListNode node1 = new ListNode(2);
        ListNode node2 = new ListNode(3);
        ListNode node3 = new ListNode(4);
        head.next = node1;
        node1.next = node2;
        node2.next = node3;
        ListNode list = reverseLinkedList(head);

        while (list != null) {
            System.out.print(list.val + " ");
            list = list.next;
        }
    }
}


class ListNode {
    int val;
    ListNode next;

    ListNode(int x) {
        val = x;
    }
}

5.

四、递归与递推联系:

1.递归实现指数型枚举

题目:从 1∼n 这 n个整数中随机选取任意多个,输出所有可能的选择方案

-算法思路:递归树,每个数字可以选可以不选(一个位置一个位置的数,往后深度遍历

 递归函数dfs:该函数接收一个参数u,表示当前正在处理排列中的第u个位置。
- 基准情况(*边界结束条件*):如果u > n,说明已经生成了一个完整的排列,此时打印出该排列并返回。
- 递归过程(*深度遍历递归*):从1到n遍历所有数字,对于每一个数字i:
		---  检查是否使用过:如果i没有被使用过(即used[i]为false),则进行以下操作:
						* 将i放入当前位置u(即state[u] = i)。
						* 标记i为已使用(即used[i] = true)。
						* 递归调用dfs(u + 1)以处理下一个位置。
						* 回溯:在返回到当前层之前,需要撤销之前的操作,即将state[u]重置为0,used[i]重置为				false,以便进行下一个分支的搜索。
import java.util.Scanner;

public class Main{
    public static int n;
    public static int[] state;
    public static void dfs(int u){
        if(u>n){//最后一层,已经生成了一组数,可以输出结束了;
            for(int i=1;i<=n;i++){
                if(state[i]==2){
                    System.out.print(i+" ");
                }
            }
            System.out.println();
            return;
        }
        
        state[u]=1;//1是不选,2是选
        dfs(u+1);
        state[u]=0;
        
        state[u]=2;
        dfs(u+1);
        state[u]=0;
        
    }
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        n=sc.nextInt();
        state=new int[n+1];
        dfs(1);
    }
}

2.递归实现排列型枚举

题目:把 1∼n 这 n个整数排成一行后随机打乱顺序,输出所有可能的次序。

算法思路:-依然递归搜索树,(循环依次)一个位置一个位置选(“深度遍历”),结束(到达边界)的时候将所有位置的数打印出来

import java.util.Scanner;
public class Main{
   
   public static int n;//一共n个数字
   public static int[] state;//每一个位置u的存入的数i,
   public static boolean[] used;//判断是否使用过;
    
    public static void dfs(int u){
        if(u>n){
            for(int i=1;i<=n;i++){
                System.out.print(state[i]+" ");
            }
            System.out.println();
            return;
        }
        for(int i=1;i<=n;i++){//从一到都要进行递归分支
            if(!used[i]){//如果没有用过
                state[u]=i;//第一个位置,写入i,
                used[i]=true;//i代表用过了
                dfs(u+1);
                state[u]=0;//回复状态
                used[i]=false;
            }
        }
        
    }
     public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        n=sc.nextInt();
        state=new int[n+1];
        used=new boolean[n+1];
        dfs(1);//递归搜索树
    }
}

3、递归实现组合型枚举

题目:从 1∼n 这 n个整数中随机选出 m个,输出所有可能的选择方案

import java.util.Scanner;


//基本和其他几道递归题目一样,只有一步要注意,看文中注释的地方
public class Main{
      public static int m,n;
    public static int[] state;
    
    public static void dfs(int u){
        if(u>m){
            for(int i=1;i<=m;i++){//依然是一位一位填数字
                System.out.print(state[i]+" ");
                
            }
            System.out.println();
            return;
        }
        for(int i=state[u-1]+1;i<=n;i++){//要i从上一位的数值大小开始
            state[u]=i;
            dfs(u+1);
            state[u]=0;
        }
    }
  
    
    
    
    
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        n=sc.nextInt();
        m=sc.nextInt();
        state=new int[m+1];
        dfs(1);
    }
}

4.简单的斐波那契数列输出

方法1:

//用递推计算
import java.util.Scanner;

public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        int n;
        n=sc.nextInt();
        int[] f=new int[n];
        f[0]=0;
       
        if(n==1){
            System.out.print(f[0]);
            
        }else if(n==2){
             f[1]=1;
            System.out.print(f[0]+" "+f[1]+" ");
        }else{
             f[1]=1;
            System.out.print(f[0]+" "+f[1]+" ");
            for(int i=2;i<n;i++){
            f[i]=f[i-1]+f[i-2];
            System.out.print(f[i]+" ");
            }
        }
        
    }
    
}

方法2:

 //两个数交替滚动计算
public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int a=0;
        int b=1;
       
        for(int i=1;i<=n;i++){
            System.out.print(a+" ");
            int sum=a;
            a=b;
            b+=sum;
        }
    }

5、(快排小练习)

在这里插入图片描述

import java.util.Scanner;


public class Main{
    
    
    public static void quickSort(int[] a,int left,int right){
        if(left>=right){//边界条件,如果left>=right:说明已经拍好顺序了
            return;
        }
        int i=left-1;
        int j=right+1;
        int mid=a[left+right>>1];
        while(i<j){
            do i++;while(a[i]<mid);//两个指针如果满足条件就向中间移动,如果都不满足,就交换两个数
            do j--;while(a[j]>mid);
            if(i<j){
                int temp=a[i];
                a[i]=a[j];
                a[j]=temp;
            }
        }
        quickSort(a,left,j);//分别递归排 mid 左边,和右边
        quickSort(a,j+1,right);
        
        
        
        
    }
    
    
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int k=sc.nextInt();
        int[] a=new int[n];
        
        for(int i=0;i<n;i++){
            a[i]=sc.nextInt();
            
        }
        quickSort(a,0,n-1);
        
        System.out.print(a[k-1]);
        
        
        
    }
}

6、二分查找

题目:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

class Solution {
    public int search(int[] nums, int target) {
        int length=nums.length;
        int left=0;
        int right=length-1;
        while(left<=right){//索引就是指针
            int mid=left+right>>1;
            if(target==nums[mid]){
                return mid;
            }else if(target>nums[mid]){
                left=mid+1;
            }else{
                right=mid-1;
            }
        }
        return -1;
    }
}
  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值