【数据结构-算法】:数据结构和算法的一些个人总结(Java实现)

简介: 【数据结构-算法】:数据结构和算法的一些个人总结(Java实现)

【数据结构-算法】:数据结构和算法的一些个人总结(Java实现)

文章目录

数据结构的分类

冒泡排序

选择排序

删除链表中的节点

反转链表

移除链表元素

递归实现两两交换链表中的节点

杨辉三角

移除元素

移动零

判断子序列

二叉树的最大深度

平衡二叉树

两个数组的交集

重建二叉树

样例

有关(大小)堆的一些随笔

魔术索引

二叉树的镜像

对称的二叉树

二叉树的层序遍历

二叉树的中序遍历

二叉树的后序遍历

二叉树的前序遍历

二叉树的最近公共祖先

二叉树的深度

飞地的数量

岛屿数量

将有序数组转化为二叉搜索树

判断二分图

N叉树的层序遍历

N叉树的后序遍历

N叉树的前序遍历

相同的树

第一个只出现一次的字符

红黑树性质

罗马数字转整数



数据结构的分类

线性结构:动态数组;普通队列;栈;链表;哈希表;


树形结构:二分搜索树;AVL树;红黑树;堆;线段树;Trie ;并查集;


图结构:邻接表;邻接矩阵;


抽象数据结构:线性表:动态数组、链表; 栈;队列;集合;映射(有序、无序);


冒泡排序

int temp = 0;
        boolean flag = false;
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    flag = true;
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
            if (!flag) {
                break;
            } else {
                flag = false;
            }
        }
    }

选择排序

public static void SelectSort(int [] arr,int n){
        for (int i = 0; i < n - 1; i++) {
            int index = i;
            int j;
            // 找出最小值得元素下标
            for (j = i + 1; j < n; j++) {
                if (arr[j] < arr[index]) {
                    index = j;
                }
            }
            int tmp = arr[index];
            arr[index] = arr[i];
            arr[i] = tmp;
            System.out.println(Arrays.toString(arr));
        }
    }


删除链表中的节点

给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。


返回删除后的链表的头节点。


注意:此题对比原题有改动


示例 1:


输入: head = [4,5,1,9], val = 5

输出: [4,1,9]

解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/shan-chu-lian-biao-de-jie-dian-lcof

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode deleteNode(ListNode head, int val) {
ListNode dumhead=new ListNode(-1);
dumhead.next=head;
ListNode prev=dumhead;
while(prev.next!=null)
{
    if(prev.next.val==val)
    prev.next=prev.next.next;
    else
    prev=prev.next;
}
return dumhead.next;
    }
}

解题思路:


首先定义一个虚拟节点,用来指向头结点的前面;


之后使用虚拟的节点表示出头结点;


定义一个节点表示指针,用来遍历链表;


反转链表

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。


示例:


输入: 1->2->3->4->5->NULL

输出: 5->4->3->2->1->NULL


限制:


0 <= 节点个数 <= 5000


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof

/**
 * 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 cur=reverseList(head.next);
        head.next.next=head;
        head.next=null;
        return cur;
    }
}

解题思路:


主要是利用的递归的思想,栈的本质就是递归。


主要难点就是递归的出口以及翻转的条件


出口就是当链表为null 则结束;


翻转的条件很关键:head.next.next=head; 这句话可以利用三个数字进行验证。 比如 1,2,3 ;


移除链表元素

删除链表中等于给定值 val 的所有节点。


示例:

输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
//方式一:使用虚拟头结点表示
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode dumhead=new ListNode(-1);
        dumhead.next=head; 
        ListNode prev=dumhead;
//这里假如特判head.next==null;的话 测试用例[1] 1,会无法通过,,,
//解决办法:要么不进行特判,要么只判断head==null的情况。
        // if(head==null || head.next==null)
        // return head;
        while(prev.next!=null){
            if(prev.next.val==val)
                prev.next=prev.next.next;
            else prev=prev.next;
        }
        return dumhead.next;
    }
}

//方式二:使用递归调用解决问题

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        if(head==null) return head;
        if(head.val==val)
        return removeElements(head.next,val);
        head.next=removeElements(head.next,val);
        return head;
    }
}


解题思路:在head之前创建一个虚拟的节点;之后创建一个指针变量指向虚拟节点,用来遍历所有的链表元素。


递归实现两两交换链表中的节点

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。


你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。


示例:

1->2->3->4
2->1->4->3
1
2
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
        if(head==null || head.next==null) return head;
        ListNode temp=head.next;
        head.next=swapPairs(temp.next);
        temp.next=head;
        return temp;
    }
}

杨辉三角

给定一个非负整数 *numRows,*生成杨辉三角的前 numRows 行。


在杨辉三角中,每个数是它左上方和右上方的数的和。


示例:

输入: 5
输出:
[
     [1],
    [1,1],
   [1,2,1],
  [1,3,3,1],
 [1,4,6,4,1]
]
class Solution {
    public List<List<Integer>> generate(int numRows) {
        List<List<Integer>> triangle = new ArrayList<List<Integer>>();
        if (numRows == 0) {
            return triangle;
        }
        triangle.add(new ArrayList<>());
        triangle.get(0).add(1);
        for (int rowNum = 1; rowNum < numRows; rowNum++) {
            List<Integer> row = new ArrayList<>();
            List<Integer> prevRow = triangle.get(rowNum-1);
            row.add(1);
            for (int j = 1; j < rowNum; j++) {
                row.add(prevRow.get(j-1) + prevRow.get(j));
            }
            row.add(1);
            triangle.add(row);
        }
        return triangle;
    }
}


解题思路:判断数值是否是第一位或者是最后一位,不是的话 那值就是 递归调用公式( [i-1] [j-1] + [i-1] [j] );


移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。


不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。


元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。


示例 1:


给定 nums = [3,2,2,3], val = 3,


函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。


你不需要考虑数组中超出新长度后面的元素。

示例 2:


给定 nums = [0,1,2,2,3,0,4,2], val = 2,


函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。


注意这五个元素可为任意顺序。


你不需要考虑数组中超出新长度后面的元素。


说明:


为什么返回数值是整数,但输出的答案是数组呢?


请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。


你可以想象内部操作如下:


// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝

int len = removeElement(nums, val);


// 在函数里修改输入数组对于调用者是可见的。

// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。

for (int i = 0; i < len; i++) {
  print(nums[i]);
}

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/remove-element

class Solution {
    public int removeElement(int[] nums, int val) {
        int j=0;
        for(int i =0 ;i<nums.length;i++)
        {
            if(nums[i]!=val)
            {
                nums[j]=nums[i];
                j++;
            }
        }
        return j;
    }
}

解题思路:主要就是 覆盖 ;


移动零

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


示例:


输入: [0,1,0,3,12]

输出: [1,3,12,0,0]

说明:


必须在原数组上操作,不能拷贝额外的数组。

尽量减少操作次数。


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/move-zeroes

class Solution {
    public void moveZeroes(int[] nums) {
        if(nums==null || nums.length==0) return;
        int i=0,j=0;
        for(i=0;i<nums.length;i++){
            if(nums[i]!=0){
                nums[j]=nums[i];
                j++;
            }
        }
       for(i=j;i<nums.length;i++)
       nums[i]=0;
    }
}

判断子序列

给定字符串 s 和 t ,判断 s 是否为 t 的子序列。


你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。


字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。


示例 1:

s = “abc”, t = “ahbgdc”


返回 true.


示例 2:

s = “axc”, t = “ahbgdc”


返回 false.


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/is-subsequence

class Solution {
    public boolean isSubsequence(String s, String t) {
        int i=s.length();
        int j=t.length();
        if(i==0) return true;
        if(i>j) return false;
        int is=0,it=0;
        while(it<j){
            if(t.charAt(it)==s.charAt(is)){
                is++;
                if(is==i)
                return true;
            }
            it++;
        }
        return false;
    }
}

解题思路:主要就是利用双指针的思想;


分别创建两个变量,用来指向两个字符串的首个字符,然后对字符串长的进行遍历,对比短字符串的每一位,相同则返回true;


二叉树的最大深度

给定一个二叉树,找出其最大深度。


二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。


说明: 叶子节点是指没有子节点的节点。


示例:

给定二叉树 [3,9,20,null,null,15,7],


3

/ \


9 20

/

15 7

返回它的最大深度 3 。


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int maxDepth(TreeNode root) {
        if(root==null) 
        return 0;
        else {
            int leftHight=maxDepth(root.left);
            int rightHight=maxDepth(root.right);
            return Math.max(leftHight,rightHight)+1;
        }
    }
}


解题思路:采取递归的策略,对每一个节点都调用maxDepth函数,最后求解左右高度的最大值即可。


平衡二叉树

给定一个二叉树,判断它是否是高度平衡的二叉树。


本题中,一棵高度平衡二叉树定义为:


一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。


示例 1:


给定二叉树 [3,9,20,null,null,15,7]


3

/

9 20

/

15 7

返回 true 。


示例 2:


给定二叉树 [1,2,2,3,3,null,null,4,4]


1

/

2 2

/

3 3

/

4 4

返回 false 。


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/balanced-binary-tree

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
       public boolean isBalanced(TreeNode root) {
        if (root == null) return true;
        return Math.abs(depth(root.left) - depth(root.right)) <= 1 
        && isBalanced(root.left) && isBalanced(root.right);
    }
    private int depth(TreeNode root) {
        if (root == null) return 0;
        return Math.max(depth(root.left), depth(root.right)) + 1;
    }
}

解题思路:采取递归求解;定义一个方法求解树的高度,递归调用; 保证每一个节点的左右子树都是平衡树


两个数组的交集

给定两个数组,编写一个函数来计算它们的交集。


示例 1:


输入:nums1 = [1,2,2,1], nums2 = [2,2]

输出:[2]

示例 2:


输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]

输出:[9,4]


说明:


输出结果中的每个元素一定是唯一的。

我们可以不考虑输出结果的顺序。


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/intersection-of-two-arrays

import java.util.TreeSet;
class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        TreeSet<Integer> set=new TreeSet<>();
        for(int nums:nums1){
            set.add(nums);
        }
        ArrayList<Integer> list=new ArrayList<>();
        for(int num:nums2){
            if(set.contains(num)){
                list.add(num);
                set.remove(num);
            }
        }
        int res[]=new int[list.size()];
        for(int i=0;i<list.size();i++){
            res[i]=list.get(i);
        }
        return res;
    }
}


解题思路:由于是要求解两个数组的交集,又要求唯一,自然而然想到了set集合;


这里使用一个集合,将数组1中所有元素加进集合;对第二个数组进行遍历,判断集合中是否存在数组中的元素,存在的话新建一个list集合保存下来,之后移除set中已经存在的元素;最后遍历list中的元素,保存到新的数组中即可;


重建二叉树

输入一棵二叉树前序遍历和中序遍历的结果,请重建该二叉树。


注意:


二叉树中每个节点的值都互不相同;

输入的前序遍历和中序遍历一定合法;

样例

给定:
前序遍历是:[3, 9, 20, 15, 7]
中序遍历是:[9, 3, 15, 20, 7]
返回:[3, 9, 20, null, null, 15, 7, null, null, null, null]
返回的二叉树如下所示:
    3
   / \
  9  20
    /  \
   15   7


/**
 * Definition for a binary tree node.
 * class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] pre, int[] in) {
         if(pre.length == 0 || in.length == 0 || pre.length != in.length) {
              return null;
          }
          // 拿到根结点
          TreeNode root = new TreeNode(pre[0]);
          // 找的根结点在中序遍历中的位置
          int i = 0;
          while(in[i] != root.val) {
              i++;
          }
          //确定左子树前序遍历长度
          int[] preLeft = new int[i];
          //确定左子树中序遍历长度
          int[] inLeft = new int[i];
          //确定右子树前序遍历长度
          int[] preRight = new int[in.length - i -1];
          //确定右子树中序遍历长度
          int[] inRight = new int[in.length - i -1];
          // 遍历 依次拿到左右子树  前中序遍历的值
          for(int j = 0 ; j<in.length ;j++) {
              if(j < i) {
                  preLeft[j] = pre[j+1];
                  inLeft[j] = in[j];
              }else if(j > i) {
                  preRight[j-i-1] = pre[j];
                  inRight[j-i-1] = in[j];
              }
          }
          // 递归
          root.left = buildTree(preLeft,inLeft);
          root.right = buildTree(preRight,inRight);
          return root;
    }
}


有关(大小)堆的一些随笔

大顶堆


首先可以使用数组存起每一个节点,利用索引表示根节点与左右子树之间的关系;


关系为:根节点=index(可以从零开始,后边的左右子树表示时 减去1 即可);左子树=index*2;右子树=index*2+1;


1.插入add插入元素到堆尾,然后上浮

 2.删除 remove 将堆首与堆尾交换,之后删掉堆尾,然后堆首下沉/上浮

 3.上浮 ;比较该节点与其父节点大小,若不符合大顶堆的根节点最大原则,则与根节点交换位置,并且指向该父节点,继续循环比较至堆顶

 4.下沉:比较父节点与左右子节点,交换不符合顺序的根节点,之后指向子节点,直至最后


大顶堆 原则上与大顶堆相同;


魔术索引

魔术索引。 在数组A[0…n-1]中,有所谓的魔术索引,满足条件A[i] = i。给定一个有序整数数组,编写一种方法找出魔术索引,若有的话,在数组A中找出一个魔术索引,如果没有,则返回-1。若有多个魔术索引,返回索引值最小的一个。


示例1:


输入:nums = [0, 2, 3, 4, 5]

输出:0

说明: 0下标的元素为0

示例2:


输入:nums = [1, 1, 1]

输出:1

说明:


nums长度在[1, 1000000]之间

此题为原书中的 Follow-up,即数组中可能包含重复元素的版本


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/magic-index-lcci

class Solution {
    public int findMagicIndex(int[] nums) {
        if(nums==null || nums.length==0)
        return -1;
        for(int i=0;i<nums.length;i++){
            if(nums[i]==i)
            return i;
        }
        return -1;
    }
}

解题思路:由于题目中数组是有序的,所以返回值一定就是最小的答案。


二叉树的镜像

请完成一个函数,输入一个二叉树,该函数输出它的镜像。


例如输入:


4

/

2 7

/ \ /

1 3 6 9

镜像输出:


4

/

7 2

/ \ /

9 6 3 1


示例 1:


输入:root = [4,2,7,1,3,6,9]

输出:[4,7,2,9,6,3,1]


限制:


0 <= 节点个数 <= 1000


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/er-cha-shu-de-jing-xiang-lcof

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode mirrorTree(TreeNode root) {
        if(root==null) return null;
        return swap(root); 
    }
    private TreeNode swap(TreeNode node){
        if(node==null) return null;
        if( node.left!=null || node.right!=null){
            TreeNode newnode=new TreeNode();
            newnode=node.left;
            node.left=node.right;
            node.right=newnode;
            swap(node.left);
            swap(node.right);
        }
        return node;
    }
}

解题思路:主要还是使用递归思想;对每一个节点都进行判断;如果有左子树或者右子树就进行节点之间的交换即可。


对称的二叉树

请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。


例如,二叉树 [1,2,2,3,4,4,3] 是对称的。


1

/

2 2

/ \ /

3 4 4 3

但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:


1

/

2 2

\

3 3


示例 1:


输入:root = [1,2,2,3,4,4,3]

输出:true

示例 2:


输入:root = [1,2,2,null,3,null,3]

输出:false


限制:


0 <= 节点个数 <= 1000


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/dui-cheng-de-er-cha-shu-lcof

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root==null) return true;
        return recur(root.left,root.right);
    }
    boolean recur(TreeNode L, TreeNode R) {
        if(L == null && R == null) return true;
        if(L == null || R == null || L.val != R.val) return false;
        return recur(L.left, R.right) && recur(L.right, R.left);
    }
}

二叉树的层序遍历

给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。


示例:

二叉树:[3,9,20,null,null,15,7],


3

/

9 20

/

15 7

返回其层次遍历结果:


[

[3],

[9,20],

[15,7]

]


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
import java.util.*;    
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        if(root==null) {
            return new ArrayList<List<Integer>>();
        }
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
        //将根节点放入队列中,然后不断遍历队列
        queue.add(root);
        while(queue.size()>0) {
            //获取当前队列的长度,这个长度相当于 当前这一层的节点个数
            int size = queue.size();
            ArrayList<Integer> tmp = new ArrayList<Integer>();
            //将队列中的元素都拿出来(也就是获取这一层的节点),放到临时list中
            //如果节点的左/右子树不为空,也放入队列中
            for(int i=0;i<size;++i) {
                TreeNode t = queue.remove();
                tmp.add(t.val);
                if(t.left!=null) {
                    queue.add(t.left);
                }
                if(t.right!=null) {
                    queue.add(t.right);
                }
            }
            //将临时list加入最终返回结果中
            res.add(tmp);
        }
        return res;
    }
}

二叉树的中序遍历

给定一个二叉树,返回它的中序 遍历。


示例:


输入: [1,null,2,3]

1


2

/

3


输出: [1,3,2]


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List list=new ArrayList<>();
        if(root==null) return list;
        return help(root,list);
    }
    private List help(TreeNode node, List list){
        if(node==null) return list;
        help(node.left,list);
        list.add(node.val);
        help(node.right,list);
        return list;
    }
}


二叉树的后序遍历

给定一个二叉树,返回它的 后序 遍历。


示例:


输入: [1,null,2,3]

1


2

/

3


输出: [3,2,1]


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/binary-tree-postorder-traversal

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list=new ArrayList<Integer>();
        if(root==null) return list;
        return help(root,list);
    }
    private List<Integer> help(TreeNode node , List<Integer> list){
        if(node==null) return list;
        help(node.left,list);
        help(node.right,list);
        list.add(node.val);
        return list;
    }
}

二叉树的前序遍历

给定一个二叉树,返回它的 前序 遍历。


示例:


输入: [1,null,2,3]

1


2

/

3


输出: [1,2,3]


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/binary-tree-preorder-traversal


递归实现:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if(root ==null) return list;
        help(root,list);
        return list;
    }
    public List<Integer> help(TreeNode node ,List<Integer> list){
        if(node==null )return list;
        list.add(node.val);
        help(node.left,list);
        help(node.right,list);
        return list;
    }
}

迭代实现:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<Integer>();
        Stack<TreeNode> stack = new Stack<>();
        if(root == null)
            return list;
        stack.push(root);
        while(!stack.isEmpty()){
            root = stack.pop();
            list.add(root.val);
            if(root.right != null)
                stack.push(root.right);
            if(root.left != null)
                stack.push(root.left);
        }
        return list; 
    }
}


二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。


百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”


例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]


image.png


示例 1:


输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1

输出: 3

解释: 节点 5 和节点 1 的最近公共祖先是节点 3。

示例 2:


输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4

输出: 5

解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/er-cha-shu-de-zui-jin-gong-gong-zu-xian-lcof

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null || q==root || p==root) return root;
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        if(left == null) return right;
        if(right == null) return left;
        return root;
    }
}


二叉树的深度

输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。


例如:


给定二叉树 [3,9,20,null,null,15,7],


3

/

9 20

/

15 7

返回它的最大深度 3 。


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/er-cha-shu-de-shen-du-lcof

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int maxDepth(TreeNode root) {
        if(root==null) return 0;
        return help(root);
    }
    private int help(TreeNode node){
        if(node==null) return 0;
        int  left=help(node.left);
        int  right= help(node.right);
        return Math.max(left,right)+1;
    }
}


飞地的数量

给出一个二维数组 A,每个单元格为 0(代表海)或 1(代表陆地)。


移动是指在陆地上从一个地方走到另一个地方(朝四个方向之一)或离开网格的边界。


返回网格中无法在任意次数的移动中离开网格边界的陆地单元格的数量。


示例 1:


输入:[[0,0,0,0],[1,0,1,0],[0,1,1,0],[0,0,0,0]]

输出:3

解释:

有三个 1 被 0 包围。一个 1 没有被包围,因为它在边界上。

示例 2:


输入:[[0,1,1,0],[0,0,1,0],[0,0,1,0],[0,0,0,0]]

输出:0

解释:

所有 1 都在边界上或可以到达边界。


提示:


1 <= A.length <= 500

1 <= A[i].length <= 500

0 <= A[i][j] <= 1

所有行的大小都相同


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/number-of-enclaves

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
int dire[][]={{-1,0},{0,1},{1,0},{0,-1}};
int row;
int col;
int [][] A;
public int numEnclaves(int[][] A) {
    this.A=A;
    if(A==null || A.length==0)
        return 0;
    row=A.length;
    col=A[0].length;
    int ret=0;
    for(int i=0;i<row;i++){
        if(A[i][0]==1){
            helper(i,0);
        }
        if(A[i][col-1]==1)
        {
            helper(i,col-1);
        }
    }
    for(int i=0;i<col;i++){
        if(A[0][i]==1){
            helper(0,i);
        }
        if(A[row-1][i]==1){
            helper(row-1,i);
        }
    }
    for(int i=0;i<row;i++){
        for(int j=0;j<col;j++){
            if(A[i][j]==1)
                ret++;
        }
    }
    return ret;
}
public void helper(int i,int j){
    if(i<0 || i>=row || j<0 || j>=col || A[i][j]==0)
        return;
    A[i][j]=0;
    for(int k=0;k<4;k++){
        int x=dire[k][0]+i;
        int y=dire[k][1]+j;
        helper(x,y);
    }
}
}

岛屿数量

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。


岛屿总是被水包围,并且每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成。


此外,你可以假设该网格的四条边均被水包围。


示例 1:


输入:

[

[‘1’,‘1’,‘1’,‘1’,‘0’],

[‘1’,‘1’,‘0’,‘1’,‘0’],

[‘1’,‘1’,‘0’,‘0’,‘0’],

[‘0’,‘0’,‘0’,‘0’,‘0’]

]

输出: 1

示例 2:


输入:

[

[‘1’,‘1’,‘0’,‘0’,‘0’],

[‘1’,‘1’,‘0’,‘0’,‘0’],

[‘0’,‘0’,‘1’,‘0’,‘0’],

[‘0’,‘0’,‘0’,‘1’,‘1’]

]

输出: 3

解释: 每座岛屿只能由水平和/或竖直方向上相邻的陆地连接而成。


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/number-of-islands

class Solution {
    int dir[][]={{-1,0},{0,1},{1,0},{0,-1}};
    boolean [][] visted;
    char[][] grid;
    int R;
    int C;
    public int numIslands(char[][] grid) {
        R=grid.length;
        if(R==0 ) return 0;
        C=grid[0].length;
        visted=new boolean[R][C];
        this.grid=grid;
        int res=0;
        for(int i=0;i<R;i++){
        for(int j=0;j<C;j++){
        if(grid[i][j]=='1' && !visted[i][j]){
         visted[i][j]=true;
           res++;
           bfs(i,j);
        }
        }
        }
        return res;
    }
    private void bfs(int i,int j){
            visted[i][j]=true;
         for(int d=0;d<4;d++){
                int x=i+dir[d][0];
                int y=j+dir[d][1];
                if( inarea(x,y)&& grid[x][y]=='1' && !visted[x][y] ){
                    bfs(x,y);
                }
            }
    }
    private boolean inarea(int x,int y){
        return x>=0 && y>=0 && x<R && y<C;
    }
}

将有序数组转化为二叉搜索树

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。


本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。


示例:


给定有序数组: [-10,-3,0,5,9],


一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:


0

/

-3 9

/ /

-10 5


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        return help(nums, 0, nums.length - 1);
    }
    public TreeNode help(int[] nums, int left, int right) {
        if (left > right || nums==null || nums.length==0) {
            return null;
        }
        int mid = (left + right) / 2;
        TreeNode root = new TreeNode(nums[mid]);
        root.left = help(nums, left, mid - 1);
        root.right = help(nums, mid + 1, right);
        return root;
    }
}

判断二分图

给定一个无向图graph,当这个图为二分图时返回true。


如果我们能将一个图的节点集合分割成两个独立的子集A和B,并使图中的每一条边的两个节点一个来自A集合,一个来自B集合,我们就将这个图称为二分图。


graph将会以邻接表方式给出,graph[i]表示图中与节点i相连的所有节点。每个节点都是一个在0到graph.length-1之间的整数。这图中没有自环和平行边: graph[i] 中不存在i,并且graph[i]中没有重复的值。


示例 1:

输入: [[1,3], [0,2], [1,3], [0,2]]

输出: true

解释:

无向图如下:

0----1

| |

| |

3----2

我们可以将节点分成两组: {0, 2} 和 {1, 3}。


示例 2:

输入: [[1,2,3], [0,2], [0,1,3], [0,2]]

输出: false

解释:

无向图如下:

0----1

| \ |

| \ |

3----2

我们不能将节点分割成两个独立的子集。

注意:


graph 的长度范围为 [1, 100]。

graph[i] 中的元素的范围为 [0, graph.length - 1]。

graph[i] 不会包含 i 或者有重复的值。

图是无向的: 如果j 在 graph[i]里边, 那么 i 也会在 graph[j]里边。


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/is-graph-bipartite

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
    private int[] colors;
    private int[][] graph;
    private boolean[] visited;
    public boolean isBipartite(int[][] graph) {
        this.graph=graph;
        int V=graph.length;
        visited=new boolean[V];
        colors=new int[V];
        for (int v = 0; v <V ; v++) {
            if(!visited[v])
                if(!dfs(v,0))
                 return false;
        }
        return true;
    }
    private boolean dfs(int v, int color) {
        visited[v]=true;
        colors[v]=color;
        for (int w:graph[v]) {
            if(!visited[w]){
            if(!dfs(w,1-color))
                return false;
                }
            if(colors[v]==colors[w])
                return false;
        }
        return true;
    }
}

N叉树的层序遍历

给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。


例如,给定一个 3叉树 :


image.png


返回其层序遍历:


[

[1],

[3,2,4],

[5,6]

]


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

/*
// Definition for a Node.
class Node {
    public int val;
    public List<Node> children;
    public Node() {}
    public Node(int _val) {
        val = _val;
    }
    public Node(int _val, List<Node> _children) {
        val = _val;
        children = _children;
    }
};
*/
class Solution {
    public List<List<Integer>> levelOrder(Node root) {      
        List<List<Integer>> result = new ArrayList<>();
        if (root == null) return result;
        Queue<Node> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            List<Integer> level = new ArrayList<>();
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                Node node = queue.poll();
                level.add(node.val);
                queue.addAll(node.children);
            }
            result.add(level);
        }
        return result;
    }
}

N叉树的后序遍历

给定一个 N 叉树,返回其节点值的后序遍历。


例如,给定一个 3叉树 :


image.png


返回其后序遍历: [5,6,3,2,4,1].


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

/*
// Definition for a Node.
class Node {
    public int val;
    public List<Node> children;
    public Node() {}
    public Node(int _val) {
        val = _val;
    }
    public Node(int _val, List<Node> _children) {
        val = _val;
        children = _children;
    }
};
*/
class Solution {
    List res=new ArrayList();
    public List<Integer> postorder(Node root) {
        if(root ==null) return res;
        help(root);
        return res;
    }
    private void help(Node node){
        if(node==null) return ;
        if(node.children!=null){
            int s=node.children.size();
            for(int i=0;i<s;i++)
            help(node.children.get(i));
        }
        res.add(node.val);
    }
}

N叉树的前序遍历

给定一个 N 叉树,返回其节点值的前序遍历。


例如,给定一个 3叉树 :


image.png


返回其前序遍历: [1,3,5,6,2,4]。

/*
// Definition for a Node.
class Node {
    public int val;
    public List<Node> children;
    public Node() {}
    public Node(int _val) {
        val = _val;
    }
    public Node(int _val, List<Node> _children) {
        val = _val;
        children = _children;
    }
};
*/
class Solution {
    List res=new ArrayList();
    public List<Integer> preorder(Node root) {
        if(root==null) return res;
        help(root);
        return res;
    }
   private void help(Node node){
       if(node==null) return ;
       res.add(node.val);
       if(node.children!=null){
           int s=node.children.size();
           for(int i=0;i<s;i++){
               help(node.children.get(i));
           }
       }
   }
}

类似二叉树的前序遍历


相同的树

给定两个二叉树,编写一个函数来检验它们是否相同。


如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。


示例 1:


输入:


1 1

/ \ /

2 3 2 3


[1,2,3], [1,2,3]


输出: true

示例 2:


输入:


1 1

/

2 2


[1,2], [1,null,2]


输出: false

示例 3:


输入:


1 1

/ \ /

2 1 1 2


[1,2,1], [1,1,2]


输出: false


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/same-tree

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        if(p==null && q==null)
        return true;
        if(p==null || q==null)
        return false;
        if(p.val!=q.val)
        return false;
        return isSameTree(p.left,q.left)&& isSameTree(p.right,q.right);
    }
}


第一个只出现一次的字符

在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。


示例:


s = “abaccdeff”

返回 “b”


s = “”

返回 " "


限制:


0 <= s 的长度 <= 50000


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/di-yi-ge-zhi-chu-xian-yi-ci-de-zi-fu-lcof

class Solution {
    public char firstUniqChar(String s) {
        if(s==null) return ' ';
        int fren[]=new int[26];
        for(int i=0;i<s.length();i++)
            fren[s.charAt(i)-'a']++;
        for(int i=0;i<s.length();i++)
            if(fren[s.charAt(i)-'a']==1)
            return s.charAt(i);
        return ' ';
    }
}

解题思路:由于题目给出了一个条件( s 只包含小写字母。)所以可以利用数组将26个字母全部存储,每一个索引从a–z一一对应;


之后再次遍历字符串,找到所有字符中只出现一次的字母,返回即可。


很多人用的都是哈希表解题,这题的初衷也是训练有关哈希表的理解,我这里使用数组只是帮助自己对哈希表理解起来简单点而已。


红黑树性质

害 也就是一些生硬的定义…


image.png


在定义数据结构时 默认的初始值应该是红色;红黑树跟2-3树是等价的


2-3树中若某节点为红色 则表示该节点是与父节点相融合的,也就是3节点形式。


以下所有描述都可以参考上图进行理解:


1.每个节点或者是红色的,或者是黑色的

2.根节点是黑色的

3.每一个叶子节点(最后的空节点)是黑色的

4.如果一个节点是红色的,那么他的孩子节点都是黑色的

5.从任意一个节点到叶子节点,经过的黑色节点数量是一样的


罗马数字转整数

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。


字符 数值

I        1

V       5

X      10

L       50

C      100

D      500

M    1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。


通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:


I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。

X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。

C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。

给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。


示例 1:


输入: “III”

输出: 3

示例 2:


输入: “IV”

输出: 4

示例 3:


输入: “IX”

输出: 9

示例 4:


输入: “LVIII”

输出: 58

解释: L = 50, V= 5, III = 3.

示例 5:


输入: “MCMXCIV”

输出: 1994

解释: M = 1000, CM = 900, XC = 90, IV = 4.


来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/roman-to-integer

import java.util.*;
class Solution {
    public int romanToInt(String s) {
        int sum = 0;
        int preNum = getValue(s.charAt(0));
        for(int i = 1;i < s.length(); i ++) {
            int num = getValue(s.charAt(i));
            if(preNum < num) {
                sum -= preNum;
            } else {
                sum += preNum;
            }
            preNum = num;
        }
        sum += preNum;
        return sum;
    }
    private int getValue(char ch) {
        switch(ch) {
            case 'I': return 1;
            case 'V': return 5;
            case 'X': return 10;
            case 'L': return 50;
            case 'C': return 100;
            case 'D': return 500;
            case 'M': return 1000;
            default: return 0;
        }
    }
    }
相关文章
|
2月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
56 1
|
2月前
|
机器学习/深度学习 算法 数据挖掘
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构。本文介绍了K-means算法的基本原理,包括初始化、数据点分配与簇中心更新等步骤,以及如何在Python中实现该算法,最后讨论了其优缺点及应用场景。
141 4
|
15天前
|
存储 运维 监控
探索局域网电脑监控软件:Python算法与数据结构的巧妙结合
在数字化时代,局域网电脑监控软件成为企业管理和IT运维的重要工具,确保数据安全和网络稳定。本文探讨其背后的关键技术——Python中的算法与数据结构,如字典用于高效存储设备信息,以及数据收集、异常检测和聚合算法提升监控效率。通过Python代码示例,展示了如何实现基本监控功能,帮助读者理解其工作原理并激发技术兴趣。
50 20
|
2月前
|
存储 算法 搜索推荐
Python 中数据结构和算法的关系
数据结构是算法的载体,算法是对数据结构的操作和运用。它们共同构成了计算机程序的核心,对于提高程序的质量和性能具有至关重要的作用
|
25天前
|
存储 缓存 安全
Java 集合江湖:底层数据结构的大揭秘!
小米是一位热爱技术分享的程序员,本文详细解析了Java面试中常见的List、Set、Map的区别。不仅介绍了它们的基本特性和实现类,还深入探讨了各自的使用场景和面试技巧,帮助读者更好地理解和应对相关问题。
42 5
|
2月前
|
数据采集 存储 算法
Python 中的数据结构和算法优化策略
Python中的数据结构和算法如何进行优化?
|
2月前
|
算法
数据结构之路由表查找算法(深度优先搜索和宽度优先搜索)
在网络通信中,路由表用于指导数据包的传输路径。本文介绍了两种常用的路由表查找算法——深度优先算法(DFS)和宽度优先算法(BFS)。DFS使用栈实现,适合路径问题;BFS使用队列,保证找到最短路径。两者均能有效查找路由信息,但适用场景不同,需根据具体需求选择。文中还提供了这两种算法的核心代码及测试结果,验证了算法的有效性。
114 23
|
2月前
|
算法
数据结构之蜜蜂算法
蜜蜂算法是一种受蜜蜂觅食行为启发的优化算法,通过模拟蜜蜂的群体智能来解决优化问题。本文介绍了蜜蜂算法的基本原理、数据结构设计、核心代码实现及算法优缺点。算法通过迭代更新蜜蜂位置,逐步优化适应度,最终找到问题的最优解。代码实现了单链表结构,用于管理蜜蜂节点,并通过适应度计算、节点移动等操作实现算法的核心功能。蜜蜂算法具有全局寻优能力强、参数设置简单等优点,但也存在对初始化参数敏感、计算复杂度高等缺点。
64 20
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
67 1
|
2月前
|
机器学习/深度学习 算法 C++
数据结构之鲸鱼算法
鲸鱼算法(Whale Optimization Algorithm,WOA)是由伊朗研究员Seyedali Mirjalili于2016年提出的一种基于群体智能的全局优化算法,灵感源自鲸鱼捕食时的群体协作行为。该算法通过模拟鲸鱼的围捕猎物和喷出气泡网的行为,结合全局搜索和局部搜索策略,有效解决了复杂问题的优化需求。其应用广泛,涵盖函数优化、机器学习、图像处理等领域。鲸鱼算法以其简单直观的特点,成为初学者友好型的优化工具,但同时也存在参数敏感、可能陷入局部最优等问题。提供的C++代码示例展示了算法的基本实现和运行过程。
61 0